diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a2769a2c2749d..5364c1e9f466c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,6 +52,8 @@ jobs: - name: Checkout the source code uses: actions/checkout@v4 - name: Calculate the CI job matrix + env: + COMMIT_MESSAGE: ${{ github.event.head_commit.message }} run: python3 src/ci/github-actions/calculate-job-matrix.py >> $GITHUB_OUTPUT id: jobs job: @@ -75,14 +77,6 @@ jobs: matrix: # Check the `calculate_matrix` job to see how is the matrix defined. include: ${{ fromJSON(needs.calculate_matrix.outputs.jobs) }} - # GitHub Actions fails the workflow if an empty list of jobs is provided to - # the workflow, so we need to skip this job if nothing was produced by - # the Python script. - # - # Unfortunately checking whether a list is empty is not possible in a nice - # way due to GitHub Actions expressions limits. - # This hack is taken from https://github.com/ferrocene/ferrocene/blob/d43edc6b7697cf1719ec1c17c54904ab94825763/.github/workflows/release.yml#L75-L82 - if: fromJSON(needs.calculate_matrix.outputs.jobs)[0] != null steps: - if: contains(matrix.os, 'windows') uses: msys2/setup-msys2@v2.22.0 diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index f4e409e0d4910..03584aed08d94 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -56,7 +56,7 @@ jobs: - name: install the bootstrap toolchain run: | # Extract the stage0 version - TOOLCHAIN=$(jq -r '.compiler | {version,date} | join("-")' -- src/stage0.json) + TOOLCHAIN=$(awk -F= '{a[$1]=$2} END {print(a["compiler_version"] "-" a["compiler_date"])}' src/stage0) # Install and set as default rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN rustup default $TOOLCHAIN diff --git a/Cargo.lock b/Cargo.lock index e5b5543b367fc..df4e4f326135e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -68,9 +68,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "ammonia" @@ -141,56 +141,57 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-lossy" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a0444767dbd4aea9355cb47a370eb184dbfe918875e127eff52cb9d1638181" +checksum = "6fcff6599f06e21b0165c85052ccd6e67dc388ddd1c516a9dc5f55dc8cacf004" dependencies = [ "anstyle", ] [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-svg" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6ddad447b448d6d5db36b31cbd3ff27c7af071619501998eeceab01968287a" +checksum = "bbbf0bf947d663010f0b4132f28ca08da9151f3b9035fa7578a38de521c1d1aa" dependencies = [ "anstream", "anstyle", @@ -201,9 +202,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -211,9 +212,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" dependencies = [ "backtrace", ] @@ -256,7 +257,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] @@ -276,9 +277,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" @@ -380,27 +381,24 @@ name = "bump-stage0" version = "0.1.0" dependencies = [ "anyhow", + "build_helper", "curl", "indexmap", "serde", - "serde_json", "toml 0.5.11", ] [[package]] name = "bumpalo" -version = "3.15.4" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytecount" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205" -dependencies = [ - "packed_simd", -] +checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" [[package]] name = "byteorder" @@ -479,9 +477,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.92" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41" +checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" [[package]] name = "cfg-if" @@ -509,7 +507,7 @@ dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -579,9 +577,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.1" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "885e4d7d5af40bfb99ae6f9433e292feac98d452dcb3ec3d25dfe7552b77da8c" +checksum = "dd79504325bf38b10165b02e89b4347300f855f273c4cb30c4a3209e6583275e" dependencies = [ "clap", ] @@ -595,7 +593,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] @@ -622,7 +620,7 @@ dependencies = [ "regex", "rustc_tools_util", "serde", - "syn 2.0.58", + "syn 2.0.62", "tempfile", "termize", "tokio", @@ -716,23 +714,23 @@ dependencies = [ [[package]] name = "color-print" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a858372ff14bab9b1b30ea504f2a4bc534582aee3e42ba2d41d2a7baba63d5d" +checksum = "1ee543c60ff3888934877a5671f45494dd27ed4ba25c6670b9a7576b7ed7a8c0" dependencies = [ "color-print-proc-macro", ] [[package]] name = "color-print-proc-macro" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57e37866456a721d0a404439a1adae37a31be4e0055590d053dfe6981e05003f" +checksum = "77ff1a80c5f3cb1ca7c06ffdd71b6a6dd6d8f896c42141fbd43f50ed28dcdb93" dependencies = [ "nom", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.62", ] [[package]] @@ -749,9 +747,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "colored" @@ -978,7 +976,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] @@ -989,7 +987,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] @@ -1004,7 +1002,7 @@ version = "0.1.80" dependencies = [ "itertools 0.12.1", "quote", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] @@ -1045,7 +1043,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] @@ -1055,7 +1053,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" dependencies = [ "derive_builder_core", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] @@ -1078,7 +1076,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] @@ -1167,14 +1165,14 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] name = "dissimilar" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632" +checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d" [[package]] name = "dlmalloc" @@ -1191,9 +1189,9 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "elasticlunr-rs" @@ -1218,9 +1216,9 @@ dependencies = [ [[package]] name = "ena" -version = "0.14.2" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" dependencies = [ "log", ] @@ -1233,9 +1231,9 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.33" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] @@ -1271,9 +1269,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", @@ -1314,9 +1312,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fastrand" -version = "2.0.2" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "field-offset" @@ -1336,15 +1334,15 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.4.1", "windows-sys 0.52.0", ] [[package]] name = "flate2" -version = "1.0.28" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", @@ -1352,9 +1350,9 @@ dependencies = [ [[package]] name = "fluent-bundle" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e242c601dec9711505f6d5bbff5bedd4b61b2469f2e8bb8e57ee7c9747a87ffd" +checksum = "7fe0a21ee80050c678013f82edf4b705fe2f26f1f9877593d13198612503f493" dependencies = [ "fluent-langneg", "fluent-syntax", @@ -1377,9 +1375,9 @@ dependencies = [ [[package]] name = "fluent-syntax" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0abed97648395c902868fee9026de96483933faa54ea3b40d652f7dfe61ca78" +checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" dependencies = [ "thiserror", ] @@ -1505,7 +1503,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] @@ -1577,9 +1575,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06fddc2749e0528d2813f95e050e87e52c8cbbae56223b9babf73b3e53b0cc6" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" dependencies = [ "cfg-if", "libc", @@ -1663,9 +1661,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", @@ -1943,7 +1941,7 @@ checksum = "d2abdd3a62551e8337af119c5899e600ca0c88ec8f23a46c60ba216c803dcf1a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] @@ -2055,9 +2053,9 @@ dependencies = [ [[package]] name = "intl-memoizer" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c310433e4a310918d6ed9243542a6b83ec1183df95dff8f23f87bb88a264a66f" +checksum = "fe22e020fce238ae18a6d5d8c502ee76a52a6e880d99477657e6acc30ec57bda" dependencies = [ "type-map", "unic-langid", @@ -2078,6 +2076,12 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + [[package]] name = "itertools" version = "0.11.0" @@ -2114,9 +2118,9 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.28" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] @@ -2219,7 +2223,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] @@ -2296,9 +2300,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -2384,7 +2388,7 @@ dependencies = [ "memchr", "once_cell", "opener", - "pulldown-cmark 0.10.2", + "pulldown-cmark 0.10.3", "regex", "serde", "serde_json", @@ -2615,12 +2619,11 @@ checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", - "libm", ] [[package]] @@ -2717,7 +2720,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] @@ -2760,7 +2763,7 @@ dependencies = [ "tabled", "tar", "tempfile", - "xz", + "xz2", "zip", ] @@ -2782,16 +2785,6 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" -[[package]] -name = "packed_simd" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f9f08af0c877571712e2e3e686ad79efad9657dbf0f7c3c8ba943ff6c38932d" -dependencies = [ - "cfg-if", - "num-traits", -] - [[package]] name = "pad" version = "0.1.6" @@ -2837,9 +2830,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", "parking_lot_core", @@ -2847,15 +2840,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.1", "smallvec", - "windows-targets 0.48.5", + "windows-targets 0.52.5", ] [[package]] @@ -2890,9 +2883,9 @@ dependencies = [ [[package]] name = "pest" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" dependencies = [ "memchr", "thiserror", @@ -2901,9 +2894,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" dependencies = [ "pest", "pest_generator", @@ -2911,22 +2904,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] name = "pest_meta" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" dependencies = [ "once_cell", "pest", @@ -3080,9 +3073,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ "unicode-ident", ] @@ -3126,9 +3119,9 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0530d13d87d1f549b66a3e8d0c688952abe5994e204ed62615baaf25dc029c" +checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" dependencies = [ "bitflags 2.5.0", "memchr", @@ -3138,9 +3131,9 @@ dependencies = [ [[package]] name = "pulldown-cmark-escape" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5d8f9aa0e3cbcfaf8bf00300004ee3b72f74770f9cbac93f6928771f613276b" +checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3" [[package]] name = "punycode" @@ -3156,9 +3149,9 @@ checksum = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -3261,6 +3254,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +dependencies = [ + "bitflags 2.5.0", +] + [[package]] name = "redox_users" version = "0.4.5" @@ -3436,9 +3438,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -3746,8 +3748,10 @@ name = "rustc_codegen_ssa" version = "0.0.0" dependencies = [ "ar_archive_writer", + "arrayvec", "bitflags 2.5.0", "cc", + "either", "itertools 0.12.1", "jobserver", "libc", @@ -3997,7 +4001,7 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", "unic-langid", ] @@ -4131,7 +4135,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", "synstructure", ] @@ -4162,6 +4166,7 @@ dependencies = [ "rustc_ast", "rustc_ast_lowering", "rustc_ast_passes", + "rustc_ast_pretty", "rustc_attr", "rustc_borrowck", "rustc_builtin_macros", @@ -4277,7 +4282,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", "synstructure", ] @@ -4364,6 +4369,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_infer", + "rustc_lint", "rustc_macros", "rustc_middle", "rustc_pattern_analysis", @@ -4832,9 +4838,20 @@ dependencies = [ "rustc_macros", "rustc_serialize", "rustc_span", + "rustc_type_ir_macros", "smallvec", ] +[[package]] +name = "rustc_type_ir_macros" +version = "0.0.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.62", + "synstructure", +] + [[package]] name = "rustc_version" version = "0.4.0" @@ -4929,7 +4946,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] @@ -4964,9 +4981,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.32" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags 2.5.0", "errno", @@ -4986,9 +5003,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47" +checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" [[package]] name = "ruzstd" @@ -5014,9 +5031,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -5050,11 +5067,11 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "core-foundation", "core-foundation-sys", "libc", @@ -5063,9 +5080,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" dependencies = [ "core-foundation-sys", "libc", @@ -5077,49 +5094,49 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d" dependencies = [ - "self_cell 1.0.3", + "self_cell 1.0.4", ] [[package]] name = "self_cell" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bf37232d3bb9a2c4e641ca2a11d83b5062066f88df7fed36c28772046d65ba" +checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a" [[package]] name = "semver" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" dependencies = [ "serde", ] [[package]] name = "serde" -version = "1.0.197" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] name = "serde_json" -version = "1.0.115" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "indexmap", "itoa", @@ -5226,9 +5243,9 @@ checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", @@ -5424,9 +5441,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.58" +version = "2.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" +checksum = "9f660c3bfcefb88c538776b6685a0c472e3128b51e74d48793dc2a488196e8eb" dependencies = [ "proc-macro2", "quote", @@ -5447,14 +5464,14 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] name = "sysinfo" -version = "0.30.8" +version = "0.30.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b1a378e48fb3ce3a5cf04359c456c9c98ff689bcf1c1bc6e6a31f247686f275" +checksum = "732ffa00f53e6b2af46208fba5718d9662a421049204e156328b66791ffa15ae" dependencies = [ "cfg-if", "core-foundation-sys", @@ -5598,22 +5615,22 @@ checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] @@ -5748,16 +5765,15 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -5835,7 +5851,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] @@ -5919,9 +5935,9 @@ dependencies = [ [[package]] name = "type-map" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d3364c5e96cb2ad1603037ab253ddd34d7fb72a58bdddf4b7350760fc69a46" +checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f" dependencies = [ "rustc-hash", ] @@ -6004,9 +6020,9 @@ dependencies = [ [[package]] name = "unic-langid" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238722e6d794ed130f91f4ea33e01fcff4f188d92337a21297892521c72df516" +checksum = "23dd9d1e72a73b25e07123a80776aae3e7b0ec461ef94f9151eed6ec88005a44" dependencies = [ "unic-langid-impl", "unic-langid-macros", @@ -6014,18 +6030,18 @@ dependencies = [ [[package]] name = "unic-langid-impl" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd55a2063fdea4ef1f8633243a7b0524cbeef1905ae04c31a1c9b9775c55bc6" +checksum = "0a5422c1f65949306c99240b81de9f3f15929f5a8bfe05bb44b034cc8bf593e5" dependencies = [ "tinystr", ] [[package]] name = "unic-langid-macros" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c854cefb82ff2816410ce606acbad1b3af065140907b29be9229040752b83ec" +checksum = "0da1cd2c042d3c7569a1008806b02039e7a4a2bdf8f8e96bd3c792434a0e275e" dependencies = [ "proc-macro-hack", "tinystr", @@ -6035,13 +6051,13 @@ dependencies = [ [[package]] name = "unic-langid-macros-impl" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea2a4c80deb4fb3ca51f66b5e2dd91e3642bbce52234bcf22e41668281208e4" +checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.58", + "syn 2.0.62", "unic-langid-impl", ] @@ -6112,9 +6128,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -6273,7 +6289,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", "wasm-bindgen-shared", ] @@ -6307,7 +6323,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6365,11 +6381,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -6385,7 +6401,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ "windows-core", - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -6398,7 +6414,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "syn 2.0.58", + "syn 2.0.62", "windows-metadata", ] @@ -6408,7 +6424,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -6432,7 +6448,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.5", ] [[package]] @@ -6452,17 +6468,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] @@ -6473,9 +6490,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" @@ -6485,9 +6502,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" @@ -6497,9 +6514,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" @@ -6509,9 +6532,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" @@ -6521,9 +6544,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" @@ -6533,9 +6556,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" @@ -6545,9 +6568,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" @@ -6585,15 +6608,6 @@ dependencies = [ "rustix", ] -[[package]] -name = "xz" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c887690ff2a2e233e8e49633461521f98ec57fbff9d59a884c9a4f04ec1da34" -dependencies = [ - "xz2", -] - [[package]] name = "xz2" version = "0.1.7" @@ -6632,28 +6646,28 @@ checksum = "9e6936f0cce458098a201c245a11bef556c6a0181129c7034d10d76d1ec3a2b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", "synstructure", ] [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] @@ -6673,7 +6687,7 @@ checksum = "e6a647510471d372f2e6c2e6b7219e44d8c574d24fdc11c610a61455782f18c3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", "synstructure", ] @@ -6696,7 +6710,7 @@ checksum = "7b4e5997cbf58990550ef1f0e5124a05e47e1ebd33a84af25739be6031a62c20" dependencies = [ "proc-macro2", "quote", - "syn 2.0.58", + "syn 2.0.62", ] [[package]] diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index a95ef4c460f45..c57be5d110641 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -2,6 +2,7 @@ use std::borrow::{Borrow, Cow}; use std::cmp; use std::fmt::{self, Write}; use std::iter; +use std::num::NonZero; use std::ops::Bound; use std::ops::Deref; @@ -10,8 +11,8 @@ use tracing::debug; use crate::{ Abi, AbiAndPrefAlign, Align, FieldsShape, IndexSlice, IndexVec, Integer, LayoutS, Niche, - NonZeroUsize, Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, TargetDataLayout, - Variants, WrappingRange, + Primitive, ReprOptions, Scalar, Size, StructKind, TagEncoding, TargetDataLayout, Variants, + WrappingRange, }; // A variant is absent if it's uninhabited and only has ZST fields. @@ -327,7 +328,7 @@ pub trait LayoutCalculator { Some(LayoutS { variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Union(NonZeroUsize::new(only_variant.len())?), + fields: FieldsShape::Union(NonZero::new(only_variant.len())?), abi, largest_niche: None, align, diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 5e3f64540e4aa..a8d019c980496 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -4,7 +4,7 @@ #![cfg_attr(feature = "nightly", feature(rustdoc_internals))] use std::fmt; -use std::num::{NonZeroUsize, ParseIntError}; +use std::num::{NonZero, ParseIntError}; use std::ops::{Add, AddAssign, Mul, RangeInclusive, Sub}; use std::str::FromStr; @@ -926,6 +926,41 @@ impl Integer { } } +/// Floating-point types. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] +pub enum Float { + F16, + F32, + F64, + F128, +} + +impl Float { + pub fn size(self) -> Size { + use Float::*; + + match self { + F16 => Size::from_bits(16), + F32 => Size::from_bits(32), + F64 => Size::from_bits(64), + F128 => Size::from_bits(128), + } + } + + pub fn align(self, cx: &C) -> AbiAndPrefAlign { + use Float::*; + let dl = cx.data_layout(); + + match self { + F16 => dl.f16_align, + F32 => dl.f32_align, + F64 => dl.f64_align, + F128 => dl.f128_align, + } + } +} + /// Fundamental unit of memory access and layout. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] @@ -938,10 +973,7 @@ pub enum Primitive { /// a negative integer passed by zero-extension will appear positive in /// the callee, and most operations on it will produce the wrong values. Int(Integer, bool), - F16, - F32, - F64, - F128, + Float(Float), Pointer(AddressSpace), } @@ -952,10 +984,7 @@ impl Primitive { match self { Int(i, _) => i.size(), - F16 => Size::from_bits(16), - F32 => Size::from_bits(32), - F64 => Size::from_bits(64), - F128 => Size::from_bits(128), + Float(f) => f.size(), // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in // different address spaces can have different sizes // (but TargetDataLayout doesn't currently parse that part of the DL string) @@ -969,10 +998,7 @@ impl Primitive { match self { Int(i, _) => i.align(dl), - F16 => dl.f16_align, - F32 => dl.f32_align, - F64 => dl.f64_align, - F128 => dl.f128_align, + Float(f) => f.align(dl), // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in // different address spaces can have different alignments // (but TargetDataLayout doesn't currently parse that part of the DL string) @@ -1149,7 +1175,7 @@ pub enum FieldsShape { Primitive, /// All fields start at no offset. The `usize` is the field count. - Union(NonZeroUsize), + Union(NonZero), /// Array/vector-like placement, with all fields of identical types. Array { stride: Size, count: u64 }, diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index fa378e19f71ab..7951b7e7b75a0 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1422,7 +1422,7 @@ pub enum ExprKind { /// of `if` / `while` expressions. (e.g., `if let 0 = x { .. }`). /// /// `Span` represents the whole `let pat = expr` statement. - Let(P, P, Span, Option), + Let(P, P, Span, Recovered), /// An `if` block, with an optional `else` block. /// /// `if expr { block } else { expr }` @@ -2164,7 +2164,7 @@ pub enum TyKind { MacCall(P), /// Placeholder for a `va_list`. CVarArgs, - /// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZeroU32`, + /// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZero`, /// just as part of the type system. Pat(P, P), /// Sometimes we need a dummy value when no error has occurred. @@ -2729,7 +2729,7 @@ pub enum UseTreeKind { /// `use prefix` or `use prefix as rename` Simple(Option), /// `use prefix::{...}` - Nested(ThinVec<(UseTree, NodeId)>), + Nested { items: ThinVec<(UseTree, NodeId)>, span: Span }, /// `use prefix::*` Glob, } @@ -2881,17 +2881,20 @@ pub struct FieldDef { pub is_placeholder: bool, } +/// Was parsing recovery performed? +#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic)] +pub enum Recovered { + No, + Yes(ErrorGuaranteed), +} + /// Fields and constructor ids of enum variants and structs. #[derive(Clone, Encodable, Decodable, Debug)] pub enum VariantData { /// Struct variant. /// /// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`. - Struct { - fields: ThinVec, - // FIXME: investigate making this a `Option` - recovered: bool, - }, + Struct { fields: ThinVec, recovered: Recovered }, /// Tuple variant. /// /// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 4d28ef56df173..379c2e273eb1c 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -441,7 +441,7 @@ fn noop_visit_use_tree(use_tree: &mut UseTree, vis: &mut T) { vis.visit_path(prefix); match kind { UseTreeKind::Simple(rename) => visit_opt(rename, |rename| vis.visit_ident(rename)), - UseTreeKind::Nested(items) => { + UseTreeKind::Nested { items, .. } => { for (tree, id) in items { vis.visit_use_tree(tree); vis.visit_id(id); diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 6e94653074904..72f89737f9952 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -167,7 +167,7 @@ impl LitKind { pub fn descr(self) -> &'static str { match self { - Bool => panic!("literal token contains `Lit::Bool`"), + Bool => "boolean", Byte => "byte", Char => "char", Integer => "integer", diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index aadcfa7fed594..8e80161af1bf4 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -706,7 +706,7 @@ impl<'t> Iterator for RefTokenTreeCursor<'t> { /// involve associated types) for getting individual elements, or /// `RefTokenTreeCursor` if you really want an `Iterator`, e.g. in a `for` /// loop. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct TokenTreeCursor { pub stream: TokenStream, index: usize, diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index f21a9cabb81be..f6e9e1a87c4bb 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -1,34 +1,88 @@ -//! Routines the parser uses to classify AST nodes - -// Predicates on exprs and stmts that the pretty-printer and parser use +//! Routines the parser and pretty-printer use to classify AST nodes. +use crate::ast::ExprKind::*; use crate::{ast, token::Delimiter}; -/// Does this expression require a semicolon to be treated -/// as a statement? The negation of this: 'can this expression -/// be used as a statement without a semicolon' -- is used -/// as an early-bail-out in the parser so that, for instance, -/// if true {...} else {...} -/// |x| 5 -/// isn't parsed as (if true {...} else {...} | x) | 5 -pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool { - !matches!( +/// This classification determines whether various syntactic positions break out +/// of parsing the current expression (true) or continue parsing more of the +/// same expression (false). +/// +/// For example, it's relevant in the parsing of match arms: +/// +/// ```ignore (illustrative) +/// match ... { +/// // Is this calling $e as a function, or is it the start of a new arm +/// // with a tuple pattern? +/// _ => $e ( +/// ^ ) +/// +/// // Is this an Index operation, or new arm with a slice pattern? +/// _ => $e [ +/// ^ ] +/// +/// // Is this a binary operator, or leading vert in a new arm? Same for +/// // other punctuation which can either be a binary operator in +/// // expression or unary operator in pattern, such as `&` and `-`. +/// _ => $e | +/// ^ +/// } +/// ``` +/// +/// If $e is something like `{}` or `if … {}`, then terminate the current +/// arm and parse a new arm. +/// +/// If $e is something like `path::to` or `(…)`, continue parsing the same +/// arm. +/// +/// *Almost* the same classification is used as an early bail-out for parsing +/// statements. See `expr_requires_semi_to_be_stmt`. +pub fn expr_is_complete(e: &ast::Expr) -> bool { + matches!( e.kind, - ast::ExprKind::If(..) - | ast::ExprKind::Match(..) - | ast::ExprKind::Block(..) - | ast::ExprKind::While(..) - | ast::ExprKind::Loop(..) - | ast::ExprKind::ForLoop { .. } - | ast::ExprKind::TryBlock(..) - | ast::ExprKind::ConstBlock(..) + If(..) + | Match(..) + | Block(..) + | While(..) + | Loop(..) + | ForLoop { .. } + | TryBlock(..) + | ConstBlock(..) ) } +/// Does this expression require a semicolon to be treated as a statement? +/// +/// The negation of this: "can this expression be used as a statement without a +/// semicolon" -- is used as an early bail-out when parsing statements so that, +/// for instance, +/// +/// ```ignore (illustrative) +/// if true {...} else {...} +/// |x| 5 +/// ``` +/// +/// isn't parsed as `(if true {...} else {...} | x) | 5`. +/// +/// Surprising special case: even though braced macro calls like `m! {}` +/// normally do not introduce a boundary when found at the head of a match arm, +/// they do terminate the parsing of a statement. +/// +/// ```ignore (illustrative) +/// match ... { +/// _ => m! {} (), // macro that expands to a function, which is then called +/// } +/// +/// let _ = { m! {} () }; // macro call followed by unit +/// ``` +pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool { + match &e.kind { + MacCall(mac_call) => mac_call.args.delim != Delimiter::Brace, + _ => !expr_is_complete(e), + } +} + /// If an expression ends with `}`, returns the innermost expression ending in the `}` pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> { - use ast::ExprKind::*; - loop { match &expr.kind { AddrOf(_, _, e) diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 1d8fd63e4592e..d36193ef7b0ab 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -517,8 +517,8 @@ pub fn walk_use_tree<'a, V: Visitor<'a>>( visit_opt!(visitor, visit_ident, rename); } UseTreeKind::Glob => {} - UseTreeKind::Nested(ref use_trees) => { - for &(ref nested_tree, nested_id) in use_trees { + UseTreeKind::Nested { ref items, .. } => { + for &(ref nested_tree, nested_id) in items { try_visit!(visitor.visit_use_tree(nested_tree, nested_id, true)); } } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 5cc05d7336eed..a553109092842 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -158,13 +158,13 @@ impl<'hir> LoweringContext<'_, 'hir> { let ohs = self.lower_expr(ohs); hir::ExprKind::AddrOf(*k, *m, ohs) } - ExprKind::Let(pat, scrutinee, span, is_recovered) => { + ExprKind::Let(pat, scrutinee, span, recovered) => { hir::ExprKind::Let(self.arena.alloc(hir::LetExpr { span: self.lower_span(*span), pat: self.lower_pat(pat), ty: None, init: self.lower_expr(scrutinee), - is_recovered: *is_recovered, + recovered: *recovered, })) } ExprKind::If(cond, then, else_opt) => { @@ -581,8 +581,8 @@ impl<'hir> LoweringContext<'_, 'hir> { self.dcx().emit_err(NeverPatternWithGuard { span: g.span }); } - // We add a fake `loop {}` arm body so that it typecks to `!`. - // FIXME(never_patterns): Desugar into a call to `unreachable_unchecked`. + // We add a fake `loop {}` arm body so that it typecks to `!`. The mir lowering of never + // patterns ensures this loop is not reachable. let block = self.arena.alloc(hir::Block { stmts: &[], expr: None, diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 156e369c45852..61fb5c16ad612 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -135,8 +135,8 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_item_id_use_tree(&mut self, tree: &UseTree, vec: &mut SmallVec<[hir::ItemId; 1]>) { match &tree.kind { - UseTreeKind::Nested(nested_vec) => { - for &(ref nested, id) in nested_vec { + UseTreeKind::Nested { items, .. } => { + for &(ref nested, id) in items { vec.push(hir::ItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(id) }, }); @@ -518,7 +518,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let path = self.lower_use_path(res, &path, ParamMode::Explicit); hir::ItemKind::Use(path, hir::UseKind::Glob) } - UseTreeKind::Nested(ref trees) => { + UseTreeKind::Nested { items: ref trees, .. } => { // Nested imports are desugared into simple imports. // So, if we start with // diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 6c54363e306d0..a76935761f0a4 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1283,7 +1283,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fields.iter().enumerate().map(|f| this.lower_field_def(f)), ); let span = t.span; - let variant_data = hir::VariantData::Struct { fields, recovered: false }; + let variant_data = + hir::VariantData::Struct { fields, recovered: ast::Recovered::No }; // FIXME: capture the generics from the outer adt. let generics = hir::Generics::empty(); let kind = match t.kind { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 2c176828c841f..b7bdb2e14a6da 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1238,7 +1238,11 @@ impl<'a> State<'a> { if let Some((init, els)) = loc.kind.init_else_opt() { self.nbsp(); self.word_space("="); - self.print_expr(init, FixupContext::default()); + self.print_expr_cond_paren( + init, + els.is_some() && classify::expr_trailing_brace(init).is_some(), + FixupContext::default(), + ); if let Some(els) = els { self.cbox(INDENT_UNIT); self.ibox(INDENT_UNIT); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 93400c67949d9..1e117c46b6e29 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -780,7 +780,7 @@ impl<'a> State<'a> { } _ => { self.end(); // Close the ibox for the pattern. - self.print_expr(body, FixupContext::new_stmt()); + self.print_expr(body, FixupContext::new_match_arm()); self.word(","); } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs index d21cb82f83b28..86d4796e9ce3b 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs @@ -49,6 +49,38 @@ pub(crate) struct FixupContext { /// No parentheses required. leftmost_subexpression_in_stmt: bool, + /// Print expression such that it can be parsed as a match arm. + /// + /// This is almost equivalent to `stmt`, but the grammar diverges a tiny bit + /// between statements and match arms when it comes to braced macro calls. + /// Macro calls with brace delimiter terminate a statement without a + /// semicolon, but do not terminate a match-arm without comma. + /// + /// ```ignore (illustrative) + /// m! {} - 1; // two statements: a macro call followed by -1 literal + /// + /// match () { + /// _ => m! {} - 1, // binary subtraction operator + /// } + /// ``` + match_arm: bool, + + /// This is almost equivalent to `leftmost_subexpression_in_stmt`, other + /// than for braced macro calls. + /// + /// If we have `m! {} - 1` as an expression, the leftmost subexpression + /// `m! {}` will need to be parenthesized in the statement case but not the + /// match-arm case. + /// + /// ```ignore (illustrative) + /// (m! {}) - 1; // subexpression needs parens + /// + /// match () { + /// _ => m! {} - 1, // no parens + /// } + /// ``` + leftmost_subexpression_in_match_arm: bool, + /// This is the difference between: /// /// ```ignore (illustrative) @@ -68,6 +100,8 @@ impl Default for FixupContext { FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, + match_arm: false, + leftmost_subexpression_in_match_arm: false, parenthesize_exterior_struct_lit: false, } } @@ -76,13 +110,16 @@ impl Default for FixupContext { impl FixupContext { /// Create the initial fixup for printing an expression in statement /// position. - /// - /// This is currently also used for printing an expression as a match-arm, - /// but this is incorrect and leads to over-parenthesizing. pub fn new_stmt() -> Self { FixupContext { stmt: true, ..FixupContext::default() } } + /// Create the initial fixup for printing an expression as the right-hand + /// side of a match arm. + pub fn new_match_arm() -> Self { + FixupContext { match_arm: true, ..FixupContext::default() } + } + /// Create the initial fixup for printing an expression as the "condition" /// of an `if` or `while`. There are a few other positions which are /// grammatically equivalent and also use this, such as the iterator @@ -106,6 +143,9 @@ impl FixupContext { FixupContext { stmt: false, leftmost_subexpression_in_stmt: self.stmt || self.leftmost_subexpression_in_stmt, + match_arm: false, + leftmost_subexpression_in_match_arm: self.match_arm + || self.leftmost_subexpression_in_match_arm, ..self } } @@ -119,7 +159,13 @@ impl FixupContext { /// example the `$b` in `$a + $b` and `-$b`, but not the one in `[$b]` or /// `$a.f($b)`. pub fn subsequent_subexpression(self) -> Self { - FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..self } + FixupContext { + stmt: false, + leftmost_subexpression_in_stmt: false, + match_arm: false, + leftmost_subexpression_in_match_arm: false, + ..self + } } /// Determine whether parentheses are needed around the given expression to @@ -128,7 +174,8 @@ impl FixupContext { /// The documentation on `FixupContext::leftmost_subexpression_in_stmt` has /// examples. pub fn would_cause_statement_boundary(self, expr: &Expr) -> bool { - self.leftmost_subexpression_in_stmt && !classify::expr_requires_semi_to_be_stmt(expr) + (self.leftmost_subexpression_in_stmt && !classify::expr_requires_semi_to_be_stmt(expr)) + || (self.leftmost_subexpression_in_match_arm && classify::expr_is_complete(expr)) } /// Determine whether parentheses are needed around the given `let` diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 61398f7d60579..09f9ca53a7ac0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -715,7 +715,7 @@ impl<'a> State<'a> { } self.word("*"); } - ast::UseTreeKind::Nested(items) => { + ast::UseTreeKind::Nested { items, .. } => { if !tree.prefix.segments.is_empty() { self.print_path(&tree.prefix, false, 0); self.word("::"); @@ -734,7 +734,7 @@ impl<'a> State<'a> { self.print_use_tree(&use_tree.0); if !is_last { self.word(","); - if let ast::UseTreeKind::Nested(_) = use_tree.0.kind { + if let ast::UseTreeKind::Nested { .. } = use_tree.0.kind { self.hardbreak(); } else { self.space(); diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index 64726eacca74a..b9fa46ea883ff 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -2,7 +2,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::ty::TyCtxt; use std::rc::Rc; @@ -105,8 +104,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(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() + *super::do_mir_borrowck(tcx, input_body, promoted, Some(options)).1.unwrap() } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 6c82dd1489ca2..ccc45e2829a10 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -22,6 +22,7 @@ use rustc_middle::mir::{ Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, }; +use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{ self, suggest_constraining_type_params, PredicateKind, ToPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, @@ -494,7 +495,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { { self.suggest_cloning(err, ty, expr, None, Some(move_spans)); } else if self.suggest_hoisting_call_outside_loop(err, expr) { - // The place where the the type moves would be misleading to suggest clone. + // The place where the type moves would be misleading to suggest clone. // #121466 self.suggest_cloning(err, ty, expr, None, Some(move_spans)); } diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 5ebdb69050b24..e3ad92a5b2bf5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -317,36 +317,39 @@ impl<'tcx> BorrowExplanation<'tcx> { let mut has_dyn = false; let mut failed = false; - let elaborated_args = std::iter::zip(*args, &generics.params).map(|(arg, param)| { - if let Some(ty::Dynamic(obj, _, ty::Dyn)) = arg.as_type().map(Ty::kind) { - let default = tcx.object_lifetime_default(param.def_id); - - let re_static = tcx.lifetimes.re_static; - - let implied_region = match default { - // This is not entirely precise. - ObjectLifetimeDefault::Empty => re_static, - ObjectLifetimeDefault::Ambiguous => { - failed = true; - re_static - } - ObjectLifetimeDefault::Param(param_def_id) => { - let index = generics.param_def_id_to_index[¶m_def_id] as usize; - args.get(index).and_then(|arg| arg.as_region()).unwrap_or_else(|| { + let elaborated_args = + std::iter::zip(*args, &generics.own_params).map(|(arg, param)| { + if let Some(ty::Dynamic(obj, _, ty::Dyn)) = arg.as_type().map(Ty::kind) { + let default = tcx.object_lifetime_default(param.def_id); + + let re_static = tcx.lifetimes.re_static; + + let implied_region = match default { + // This is not entirely precise. + ObjectLifetimeDefault::Empty => re_static, + ObjectLifetimeDefault::Ambiguous => { failed = true; re_static - }) - } - ObjectLifetimeDefault::Static => re_static, - }; + } + ObjectLifetimeDefault::Param(param_def_id) => { + let index = generics.param_def_id_to_index[¶m_def_id] as usize; + args.get(index).and_then(|arg| arg.as_region()).unwrap_or_else( + || { + failed = true; + re_static + }, + ) + } + ObjectLifetimeDefault::Static => re_static, + }; - has_dyn = true; + has_dyn = true; - Ty::new_dynamic(tcx, obj, implied_region, ty::Dyn).into() - } else { - arg - } - }); + Ty::new_dynamic(tcx, obj, implied_region, ty::Dyn).into() + } else { + arg + } + }); let elaborated_ty = Ty::new_adt(tcx, *def, tcx.mk_args_from_iter(elaborated_args)); if has_dyn && !failed { diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 0b4018a23ce7b..88172c62a3b2d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1344,7 +1344,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Applicability::MaybeIncorrect, ); for error in errors { - if let FulfillmentErrorCode::SelectionError( + if let FulfillmentErrorCode::Select( SelectionError::Unimplemented, ) = error.code && let ty::PredicateKind::Clause(ty::ClauseKind::Trait( diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 5d74a01aa2076..c9a09c19ce63d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1283,7 +1283,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } // The type doesn't implement Clone because of unmet obligations. for error in errors { - if let traits::FulfillmentErrorCode::SelectionError( + if let traits::FulfillmentErrorCode::Select( traits::SelectionError::Unimplemented, ) = error.code && let ty::PredicateKind::Clause(ty::ClauseKind::Trait( @@ -1483,10 +1483,9 @@ fn suggest_ampmut<'tcx>( } else { // otherwise, suggest that the user annotates the binding; we provide the // type of the local. - let ty_mut = decl_ty.builtin_deref(true).unwrap(); - assert_eq!(ty_mut.mutbl, hir::Mutability::Not); + let ty = decl_ty.builtin_deref(true).unwrap(); - (false, span, format!("{}mut {}", if decl_ty.is_ref() { "&" } else { "*" }, ty_mut.ty)) + (false, span, format!("{}mut {}", if decl_ty.is_ref() { "&" } else { "*" }, ty)) } } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 47c83e0bb2bb6..abe57e26af461 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -23,9 +23,8 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::{BitSet, ChunkedBitSet}; use rustc_index::{IndexSlice, IndexVec}; -use rustc_infer::infer::{ - InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, -}; +use rustc_infer::infer::TyCtxtInferExt; +use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin}; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::*; use rustc_middle::query::Providers; @@ -123,9 +122,8 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> { return tcx.arena.alloc(result); } - 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; + let opt_closure_req = do_mir_borrowck(tcx, input_body, promoted, None).0; debug!("mir_borrowck done"); tcx.arena.alloc(opt_closure_req) @@ -136,18 +134,15 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> { /// Use `consumer_options: None` for the default behavior of returning /// [`BorrowCheckResult`] only. Otherwise, return [`BodyWithBorrowckFacts`] according /// to the given [`ConsumerOptions`]. -#[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.def_id()), level = "debug")] +#[instrument(skip(tcx, input_body, input_promoted), fields(id=?input_body.source.def_id()), level = "debug")] fn do_mir_borrowck<'tcx>( - infcx: &InferCtxt<'tcx>, + tcx: TyCtxt<'tcx>, input_body: &Body<'tcx>, input_promoted: &IndexSlice>, consumer_options: Option, ) -> (BorrowCheckResult<'tcx>, Option>>) { let def = input_body.source.def_id().expect_local(); - debug!(?def); - - let tcx = infcx.tcx; - let infcx = BorrowckInferCtxt::new(infcx); + let infcx = BorrowckInferCtxt::new(tcx, def); let param_env = tcx.param_env(def); let mut local_names = IndexVec::from_elem(None, &input_body.local_decls); @@ -187,6 +182,12 @@ fn do_mir_borrowck<'tcx>( nll::replace_regions_in_mir(&infcx, param_env, &mut body_owned, &mut promoted); let body = &body_owned; // no further changes + // FIXME(-Znext-solver): A bit dubious that we're only registering + // predefined opaques in the typeck root. + if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) { + infcx.register_predefined_opaques_for_next_solver(def); + } + let location_table = LocationTable::new(body); let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true); @@ -440,13 +441,14 @@ fn do_mir_borrowck<'tcx>( (result, body_with_facts) } -pub struct BorrowckInferCtxt<'cx, 'tcx> { - pub(crate) infcx: &'cx InferCtxt<'tcx>, +pub struct BorrowckInferCtxt<'tcx> { + pub(crate) infcx: InferCtxt<'tcx>, pub(crate) reg_var_to_origin: RefCell>, } -impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { - pub(crate) fn new(infcx: &'cx InferCtxt<'tcx>) -> Self { +impl<'tcx> BorrowckInferCtxt<'tcx> { + pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { + let infcx = tcx.infer_ctxt().with_opaque_type_inference(def_id).build(); BorrowckInferCtxt { infcx, reg_var_to_origin: RefCell::new(Default::default()) } } @@ -492,18 +494,40 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { next_region } + + /// With the new solver we prepopulate the opaque type storage during + /// MIR borrowck with the hidden types from HIR typeck. This is necessary + /// to avoid ambiguities as earlier goals can rely on the hidden type + /// of an opaque which is only constrained by a later goal. + fn register_predefined_opaques_for_next_solver(&self, def_id: LocalDefId) { + let tcx = self.tcx; + // OK to use the identity arguments for each opaque type key, since + // we remap opaques from HIR typeck back to their definition params. + for data in tcx.typeck(def_id).concrete_opaque_types.iter().map(|(k, v)| (*k, *v)) { + // HIR typeck did not infer the regions of the opaque, so we instantiate + // them with fresh inference variables. + let (key, hidden_ty) = tcx.fold_regions(data, |_, _| { + self.next_nll_region_var_in_universe( + NllRegionVariableOrigin::Existential { from_forall: false }, + ty::UniverseIndex::ROOT, + ) + }); + + self.inject_new_hidden_type_unchecked(key, hidden_ty); + } + } } -impl<'cx, 'tcx> Deref for BorrowckInferCtxt<'cx, 'tcx> { +impl<'tcx> Deref for BorrowckInferCtxt<'tcx> { type Target = InferCtxt<'tcx>; - fn deref(&self) -> &'cx Self::Target { - self.infcx + fn deref(&self) -> &Self::Target { + &self.infcx } } struct MirBorrowckCtxt<'cx, 'tcx> { - infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>, + infcx: &'cx BorrowckInferCtxt<'tcx>, param_env: ParamEnv<'tcx>, body: &'cx Body<'tcx>, move_data: &'cx MoveData<'tcx>, diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 4aa32a61f7c36..49f50babdcb96 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -51,7 +51,7 @@ pub(crate) struct NllOutput<'tcx> { /// `compute_regions`. #[instrument(skip(infcx, param_env, body, promoted), level = "debug")] pub(crate) fn replace_regions_in_mir<'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, + infcx: &BorrowckInferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexSlice>, @@ -75,7 +75,7 @@ pub(crate) fn replace_regions_in_mir<'tcx>( /// /// This may result in errors being reported. pub(crate) fn compute_regions<'cx, 'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, + infcx: &BorrowckInferCtxt<'tcx>, universal_regions: UniversalRegions<'tcx>, body: &Body<'tcx>, promoted: &IndexSlice>, @@ -202,7 +202,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>( } pub(super) fn dump_mir_results<'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, + infcx: &BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, @@ -254,7 +254,7 @@ pub(super) fn dump_mir_results<'tcx>( #[allow(rustc::diagnostic_outside_of_impl)] #[allow(rustc::untranslatable_diagnostic)] pub(super) fn dump_annotation<'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, + infcx: &BorrowckInferCtxt<'tcx>, body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index 78465ad7975d9..167ca7ba04570 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -250,10 +250,7 @@ pub enum ExtraConstraintInfo { } #[instrument(skip(infcx, sccs), level = "debug")] -fn sccs_info<'cx, 'tcx>( - infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>, - sccs: Rc>, -) { +fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: Rc>) { use crate::renumber::RegionCtxt; let var_to_origin = infcx.reg_var_to_origin.borrow(); @@ -322,8 +319,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// /// The `outlives_constraints` and `type_tests` are an initial set /// of constraints produced by the MIR type check. - pub(crate) fn new<'cx>( - _infcx: &BorrowckInferCtxt<'cx, 'tcx>, + pub(crate) fn new( + _infcx: &BorrowckInferCtxt<'tcx>, var_infos: VarInfos, universal_regions: Rc>, placeholder_indices: Rc, @@ -1329,14 +1326,20 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) } - // Evaluate whether `sup_region == sub_region`. - fn eval_equal(&self, r1: RegionVid, r2: RegionVid) -> bool { + /// Evaluate whether `sup_region == sub_region`. + /// + /// Panics if called before `solve()` executes, + // This is `pub` because it's used by unstable external borrowck data users, see `consumers.rs`. + pub fn eval_equal(&self, r1: RegionVid, r2: RegionVid) -> bool { self.eval_outlives(r1, r2) && self.eval_outlives(r2, r1) } - // Evaluate whether `sup_region: sub_region`. + /// Evaluate whether `sup_region: sub_region`. + /// + /// Panics if called before `solve()` executes, + // This is `pub` because it's used by unstable external borrowck data users, see `consumers.rs`. #[instrument(skip(self), level = "debug", ret)] - fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool { + pub fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool { debug!( "sup_region's value = {:?} universal={:?}", self.region_value_str(sup_region), @@ -2056,15 +2059,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { // We currently do not store the `DefId` in the `ConstraintCategory` // for performances reasons. The error reporting code used by NLL only // uses the span, so this doesn't cause any problems at the moment. - Some(ObligationCauseCode::BindingObligation( - CRATE_DEF_ID.to_def_id(), - predicate_span, - )) + Some(ObligationCauseCode::WhereClause(CRATE_DEF_ID.to_def_id(), predicate_span)) } else { None } }) - .unwrap_or_else(|| ObligationCauseCode::MiscObligation); + .unwrap_or_else(|| ObligationCauseCode::Misc); // Classify each of the constraints along the path. let mut categorized_path: Vec> = path @@ -2249,7 +2249,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Access to the SCC constraint graph. - pub(crate) fn constraint_sccs(&self) -> &Sccs { + /// This can be used to quickly under-approximate the regions which are equal to each other + /// and their relative orderings. + // This is `pub` because it's used by unstable external borrowck data users, see `consumers.rs`. + pub fn constraint_sccs(&self) -> &Sccs { self.constraint_sccs.as_ref() } diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 73ba5bee13b7f..f601a9d70739f 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -40,7 +40,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// compares lifetimes directly, so we need to map the inference variables /// back to concrete lifetimes: `'static`, `ReEarlyParam` or `ReLateParam`. /// - /// First we map the regions in the the generic parameters `_Return<'1>` to + /// First we map the regions in the generic parameters `_Return<'1>` to /// their `external_name` giving `_Return<'a>`. This step is a bit involved. /// See the [rustc-dev-guide chapter] for more info. /// diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index dca8df3280028..d382f264c37bd 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -11,7 +11,7 @@ use rustc_span::Symbol; /// inference variables, returning the number of variables created. #[instrument(skip(infcx, body, promoted), level = "debug")] pub fn renumber_mir<'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, + infcx: &BorrowckInferCtxt<'tcx>, body: &mut Body<'tcx>, promoted: &mut IndexSlice>, ) { @@ -26,9 +26,7 @@ pub fn renumber_mir<'tcx>( renumberer.visit_body(body); } -// FIXME(@lcnr): A lot of these variants overlap and it seems like -// this type is only used to decide which region should be used -// as representative. This should be cleaned up. +// The fields are used only for debugging output in `sccs_info`. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub(crate) enum RegionCtxt { Location(Location), @@ -57,7 +55,7 @@ impl RegionCtxt { } struct RegionRenumberer<'a, 'tcx> { - infcx: &'a BorrowckInferCtxt<'a, 'tcx>, + infcx: &'a BorrowckInferCtxt<'tcx>, } impl<'a, 'tcx> RegionRenumberer<'a, 'tcx> { diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index 2511a1535af18..4e45dc42aa722 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -11,7 +11,6 @@ use std::assert_matches::assert_matches; use itertools::Itertools; use rustc_hir as hir; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin}; use rustc_middle::mir::*; use rustc_middle::ty::{self, Ty}; @@ -74,9 +73,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { }), ); - let next_ty_var = || { - self.infcx.next_ty_var(TypeVariableOrigin { span: body.span, param_def_id: None }) - }; + let next_ty_var = || self.infcx.next_ty_var(body.span); let output_ty = Ty::new_coroutine( self.tcx(), self.tcx().coroutine_for_closure(mir_def_id), diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs index da5456692ab13..ccd9fb25739cc 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs @@ -1,4 +1,3 @@ -use rustc_data_structures::vec_linked_list as vll; use rustc_index::IndexVec; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{Body, Local, Location}; @@ -37,9 +36,12 @@ pub(crate) struct LocalUseMap { /// we add for each local variable. first_drop_at: IndexVec>, - appearances: IndexVec, + appearances: Appearances, } +// The `Appearance::next` field effectively embeds a linked list within `Appearances`. +type Appearances = IndexVec; + struct Appearance { point_index: PointIndex, next: Option, @@ -49,14 +51,34 @@ rustc_index::newtype_index! { pub struct AppearanceIndex {} } -impl vll::LinkElem for Appearance { - type LinkIndex = AppearanceIndex; +fn appearances_iter( + first: Option, + appearances: &Appearances, +) -> impl Iterator + '_ { + AppearancesIter { appearances, current: first } +} + +// Iterates over `Appearances` by following `next` fields. +struct AppearancesIter<'a> { + appearances: &'a Appearances, + current: Option, +} - fn next(elem: &Self) -> Option { - elem.next +impl<'a> Iterator for AppearancesIter<'a> { + type Item = AppearanceIndex; + + fn next(&mut self) -> Option { + if let Some(c) = self.current { + self.current = self.appearances[c].next; + Some(c) + } else { + None + } } } +//----------------------------------------------------------------------------- + impl LocalUseMap { pub(crate) fn build( live_locals: &[Local], @@ -86,17 +108,17 @@ impl LocalUseMap { } pub(crate) fn defs(&self, local: Local) -> impl Iterator + '_ { - vll::iter(self.first_def_at[local], &self.appearances) + appearances_iter(self.first_def_at[local], &self.appearances) .map(move |aa| self.appearances[aa].point_index) } pub(crate) fn uses(&self, local: Local) -> impl Iterator + '_ { - vll::iter(self.first_use_at[local], &self.appearances) + appearances_iter(self.first_use_at[local], &self.appearances) .map(move |aa| self.appearances[aa].point_index) } pub(crate) fn drops(&self, local: Local) -> impl Iterator + '_ { - vll::iter(self.first_drop_at[local], &self.appearances) + appearances_iter(self.first_drop_at[local], &self.appearances) .map(move |aa| self.appearances[aa].point_index) } } @@ -146,7 +168,7 @@ impl LocalUseMapBuild<'_> { fn insert( elements: &DenseLocationMap, first_appearance: &mut Option, - appearances: &mut IndexVec, + appearances: &mut Appearances, location: Location, ) { let point_index = elements.point_from_location(location); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index b67c5d8581839..2740e9689c51f 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -16,7 +16,6 @@ use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::region_constraints::RegionConstraintData; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::{ BoundRegion, BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, }; @@ -24,7 +23,6 @@ use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::visit::TypeVisitableExt; @@ -122,7 +120,7 @@ mod relate_tys; /// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis /// - `elements` -- MIR region map pub(crate) fn type_check<'mir, 'tcx>( - infcx: &BorrowckInferCtxt<'_, 'tcx>, + infcx: &BorrowckInferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body: &Body<'tcx>, promoted: &IndexSlice>, @@ -402,7 +400,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } else if let Some(static_def_id) = constant.check_static_ptr(tcx) { let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity(); let normalized_ty = self.cx.normalize(unnormalized_ty, locations); - let literal_ty = constant.const_.ty().builtin_deref(true).unwrap().ty; + let literal_ty = constant.const_.ty().builtin_deref(true).unwrap(); if let Err(terr) = self.cx.eq_types( literal_ty, @@ -534,8 +532,11 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { let tcx = self.tcx(); - let trait_ref = - ty::TraitRef::from_lang_item(tcx, LangItem::Copy, self.last_span, [place_ty.ty]); + let trait_ref = ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::Copy, Some(self.last_span)), + [place_ty.ty], + ); // To have a `Copy` operand, the type `T` of the // value must be `Copy`. Note that we prove that `T: Copy`, @@ -639,7 +640,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { match pi { ProjectionElem::Deref => { let deref_ty = base_ty.builtin_deref(true); - PlaceTy::from_ty(deref_ty.map(|t| t.ty).unwrap_or_else(|| { + PlaceTy::from_ty(deref_ty.unwrap_or_else(|| { span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty) })) } @@ -865,7 +866,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { /// way, it accrues region constraints -- these can later be used by /// NLL region checking. struct TypeChecker<'a, 'tcx> { - infcx: &'a BorrowckInferCtxt<'a, 'tcx>, + infcx: &'a BorrowckInferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, last_span: Span, body: &'a Body<'tcx>, @@ -1020,7 +1021,7 @@ impl Locations { impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn new( - infcx: &'a BorrowckInferCtxt<'a, 'tcx>, + infcx: &'a BorrowckInferCtxt<'tcx>, body: &'a Body<'tcx>, param_env: ty::ParamEnv<'tcx>, region_bound_pairs: &'a RegionBoundPairs<'tcx>, @@ -1028,7 +1029,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { implicit_region_bound: ty::Region<'tcx>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, ) -> Self { - let mut checker = Self { + Self { infcx, last_span: body.span, body, @@ -1039,74 +1040,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { implicit_region_bound, borrowck_context, reported_errors: Default::default(), - }; - - // FIXME(-Znext-solver): A bit dubious that we're only registering - // predefined opaques in the typeck root. - if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) { - checker.register_predefined_opaques_for_next_solver(); - } - - checker - } - - pub(super) fn register_predefined_opaques_for_next_solver(&mut self) { - // OK to use the identity arguments for each opaque type key, since - // we remap opaques from HIR typeck back to their definition params. - let opaques: Vec<_> = self - .infcx - .tcx - .typeck(self.body.source.def_id().expect_local()) - .concrete_opaque_types - .iter() - .map(|(k, v)| (*k, *v)) - .collect(); - - let renumbered_opaques = self.infcx.tcx.fold_regions(opaques, |_, _| { - self.infcx.next_nll_region_var_in_universe( - NllRegionVariableOrigin::Existential { from_forall: false }, - ty::UniverseIndex::ROOT, - ) - }); - - let param_env = self.param_env; - let result = self.fully_perform_op( - Locations::All(self.body.span), - ConstraintCategory::OpaqueType, - CustomTypeOp::new( - |ocx| { - let mut obligations = Vec::new(); - for (opaque_type_key, hidden_ty) in renumbered_opaques { - let cause = ObligationCause::dummy(); - ocx.infcx.insert_hidden_type( - opaque_type_key, - &cause, - param_env, - hidden_ty.ty, - &mut obligations, - )?; - - ocx.infcx.add_item_bounds_for_hidden_type( - opaque_type_key.def_id.to_def_id(), - opaque_type_key.args, - cause, - param_env, - hidden_ty.ty, - &mut obligations, - ); - } - - ocx.register_obligations(obligations); - Ok(()) - }, - "register pre-defined opaques", - ), - ); - - if result.is_err() { - self.infcx - .dcx() - .span_bug(self.body.span, "failed re-defining predefined opaques in mir typeck"); } } @@ -1343,10 +1276,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.check_rvalue(body, rv, location); if !self.unsized_feature_enabled() { - let trait_ref = ty::TraitRef::from_lang_item( + let trait_ref = ty::TraitRef::new( tcx, - LangItem::Sized, - self.last_span, + tcx.require_lang_item(LangItem::Sized, Some(self.last_span)), [place_ty], ); self.prove_trait_ref( @@ -1995,8 +1927,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Operand::Move(place) => { // Make sure that repeated elements implement `Copy`. let ty = place.ty(body, tcx).ty; - let trait_ref = - ty::TraitRef::from_lang_item(tcx, LangItem::Copy, span, [ty]); + let trait_ref = ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::Copy, Some(span)), + [ty], + ); self.prove_trait_ref( trait_ref, @@ -2009,7 +1944,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } &Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, ty) => { - let trait_ref = ty::TraitRef::from_lang_item(tcx, LangItem::Sized, span, [ty]); + let trait_ref = ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::Sized, Some(span)), + [ty], + ); self.prove_trait_ref( trait_ref, @@ -2022,7 +1961,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Rvalue::ShallowInitBox(operand, ty) => { self.check_operand(operand, location); - let trait_ref = ty::TraitRef::from_lang_item(tcx, LangItem::Sized, span, [*ty]); + let trait_ref = ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::Sized, Some(span)), + [*ty], + ); self.prove_trait_ref( trait_ref, @@ -2120,10 +2063,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { CastKind::PointerCoercion(PointerCoercion::Unsize) => { let &ty = ty; - let trait_ref = ty::TraitRef::from_lang_item( + let trait_ref = ty::TraitRef::new( tcx, - LangItem::CoerceUnsized, - span, + tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)), [op.ty(body, tcx), ty], ); @@ -2425,10 +2367,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // Types with regions are comparable if they have a common super-type. ty::RawPtr(_, _) | ty::FnPtr(_) => { let ty_right = right.ty(body, tcx); - let common_ty = self.infcx.next_ty_var(TypeVariableOrigin { - param_def_id: None, - span: body.source_info(location).span, - }); + let common_ty = self.infcx.next_ty_var(body.source_info(location).span); self.sub_types( ty_left, common_ty, diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 5e4b3e532c413..493c41e59e303 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,6 +1,5 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_infer::infer::{ObligationEmittingRelation, StructurallyRelateAliases}; use rustc_infer::traits::{Obligation, PredicateObligations}; @@ -129,10 +128,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { // by using `ty_vid rel B` and then finally and end by equating `ty_vid` to // the opaque. let mut enable_subtyping = |ty, opaque_is_expected| { - let ty_vid = infcx.next_ty_var_id_in_universe( - TypeVariableOrigin { param_def_id: None, span: self.span() }, - ty::UniverseIndex::ROOT, - ); + let ty_vid = infcx.next_ty_var_id_in_universe(self.span(), ty::UniverseIndex::ROOT); let variance = if opaque_is_expected { self.ambient_variance diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 070238fc37882..f8123535e2d0a 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -240,7 +240,7 @@ impl<'tcx> UniversalRegions<'tcx> { /// signature. This will also compute the relationships that are /// known between those regions. pub fn new( - infcx: &BorrowckInferCtxt<'_, 'tcx>, + infcx: &BorrowckInferCtxt<'tcx>, mir_def: LocalDefId, param_env: ty::ParamEnv<'tcx>, ) -> Self { @@ -411,7 +411,7 @@ impl<'tcx> UniversalRegions<'tcx> { } struct UniversalRegionsBuilder<'cx, 'tcx> { - infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>, + infcx: &'cx BorrowckInferCtxt<'tcx>, mir_def: LocalDefId, param_env: ty::ParamEnv<'tcx>, } @@ -796,7 +796,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } #[extension(trait InferCtxtExt<'tcx>)] -impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> { +impl<'tcx> BorrowckInferCtxt<'tcx> { #[instrument(skip(self), level = "debug")] fn replace_free_regions_with_nll_infer_vars( &self, diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 92efeab08ebea..085ea3458bbfa 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -120,10 +120,13 @@ impl<'cx, 'a> Context<'cx, 'a> { thin_vec![self.cx.attr_nested_word(sym::allow, sym::unused_imports, self.span)], ItemKind::Use(UseTree { prefix: self.cx.path(self.span, self.cx.std_path(&[sym::asserting])), - kind: UseTreeKind::Nested(thin_vec![ - nested_tree(self, sym::TryCaptureGeneric), - nested_tree(self, sym::TryCapturePrintable), - ]), + kind: UseTreeKind::Nested { + items: thin_vec![ + nested_tree(self, sym::TryCaptureGeneric), + nested_tree(self, sym::TryCapturePrintable), + ], + span: self.span, + }, span: self.span, }), ), diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs index dc73caa4ad5be..a6457f4a433c4 100644 --- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs +++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs @@ -31,7 +31,7 @@ pub(crate) fn expand_deriving_partial_eq( }; // We received arguments of type `&T`. Convert them to type `T` by stripping - // any leading `&` or adding `*`. This isn't necessary for type checking, but + // any leading `&`. This isn't necessary for type checking, but // it results in better error messages if something goes wrong. // // Note: for arguments that look like `&{ x }`, which occur with packed @@ -53,8 +53,7 @@ pub(crate) fn expand_deriving_partial_eq( inner.clone() } } else { - // No leading `&`: add a leading `*`. - cx.expr_deref(field.span, expr.clone()) + expr.clone() } }; cx.expr_binary( diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index d6e2d1d4d07f6..e3a93ae13e45f 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -123,7 +123,7 @@ fn assert_ty_bounds( span: Span, assert_path: &[Symbol], ) { - // Deny anonymous structs or unions to avoid wierd errors. + // Deny anonymous structs or unions to avoid weird errors. assert!(!ty.kind.is_anon_adt(), "Anonymous structs or unions cannot be type parameters"); // Generate statement `let _: assert_path;`. let span = cx.with_def_site_ctxt(span); diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 2450ac8f4b338..a5fc74f1d6669 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -7,14 +7,13 @@ use rustc_ast::{token, StmtKind}; use rustc_ast::{ Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind, FormatArguments, FormatCount, - FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait, + FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait, Recovered, }; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans}; use rustc_expand::base::*; use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId}; -use rustc_parse::parser::Recovered; use rustc_parse_format as parse; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{BytePos, ErrorGuaranteed, InnerSpan, Span}; @@ -112,7 +111,7 @@ fn parse_args<'a>(ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, _ => return Err(err), } } - Ok(Recovered::Yes) => (), + Ok(Recovered::Yes(_)) => (), Ok(Recovered::No) => unreachable!(), } } @@ -315,7 +314,7 @@ fn make_format_args( let mut used = vec![false; args.explicit_args().len()]; let mut invalid_refs = Vec::new(); - let mut numeric_refences_to_named_arg = Vec::new(); + let mut numeric_references_to_named_arg = Vec::new(); enum ArgRef<'a> { Index(usize), @@ -336,7 +335,7 @@ fn make_format_args( used[index] = true; if arg.kind.ident().is_some() { // This was a named argument, but it was used as a positional argument. - numeric_refences_to_named_arg.push((index, span, used_as)); + numeric_references_to_named_arg.push((index, span, used_as)); } Ok(index) } else { @@ -544,7 +543,7 @@ fn make_format_args( // Only check for unused named argument names if there are no other errors to avoid causing // too much noise in output errors, such as when a named argument is entirely unused. if invalid_refs.is_empty() && !has_unused && !unnamed_arg_after_named_arg { - for &(index, span, used_as) in &numeric_refences_to_named_arg { + for &(index, span, used_as) in &numeric_references_to_named_arg { let (position_sp_to_replace, position_sp_for_msg) = match used_as { Placeholder(pspan) => (span, pspan), Precision => { diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index e3d050df4cd1b..8874efadec9d9 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -670,11 +670,8 @@ fn codegen_stmt<'tcx>( let to_ty = fx.monomorphize(to_ty); fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { - ty.builtin_deref(true).is_some_and( - |ty::TypeAndMut { ty: pointee_ty, mutbl: _ }| { - has_ptr_meta(fx.tcx, pointee_ty) - }, - ) + ty.builtin_deref(true) + .is_some_and(|pointee_ty| has_ptr_meta(fx.tcx, pointee_ty)) } if is_fat_ptr(fx, from_ty) { diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index 2a24d6150bd6e..21d0cd2d30f2a 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -7,7 +7,7 @@ use rustc_middle::ty::layout::{ use rustc_middle::ty::TypeFoldable; use rustc_span::source_map::Spanned; use rustc_target::abi::call::FnAbi; -use rustc_target::abi::{Integer, Primitive}; +use rustc_target::abi::{Float, Integer, Primitive}; use rustc_target::spec::{HasTargetSpec, Target}; use crate::constant::ConstantCx; @@ -32,10 +32,12 @@ pub(crate) fn scalar_to_clif_type(tcx: TyCtxt<'_>, scalar: Scalar) -> Type { Integer::I64 => types::I64, Integer::I128 => types::I128, }, - Primitive::F16 => unimplemented!("f16_f128"), - Primitive::F32 => types::F32, - Primitive::F64 => types::F64, - Primitive::F128 => unimplemented!("f16_f128"), + Primitive::Float(float) => match float { + Float::F16 => unimplemented!("f16_f128"), + Float::F32 => types::F32, + Float::F64 => types::F64, + Float::F128 => unimplemented!("f16_f128"), + }, // FIXME(erikdesjardins): handle non-default addrspace ptr sizes Primitive::Pointer(_) => pointer_ty(tcx), } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 79a90507fa2e1..cafdc051db5ac 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -586,7 +586,7 @@ fn codegen_regular_intrinsic_call<'tcx>( intrinsic_args!(fx, args => (base, offset); intrinsic); let offset = offset.load_scalar(fx); - let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty; + let pointee_ty = base.layout().ty.builtin_deref(true).unwrap(); let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let ptr_diff = if pointee_size != 1 { fx.bcx.ins().imul_imm(offset, pointee_size as i64) @@ -610,7 +610,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let val = val.load_scalar(fx); let count = count.load_scalar(fx); - let pointee_ty = dst.layout().ty.builtin_deref(true).unwrap().ty; + let pointee_ty = dst.layout().ty.builtin_deref(true).unwrap(); let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let count = if pointee_size != 1 { fx.bcx.ins().imul_imm(count, pointee_size as i64) @@ -715,7 +715,7 @@ fn codegen_regular_intrinsic_call<'tcx>( // Cranelift treats loads as volatile by default // FIXME correctly handle unaligned_volatile_load - let inner_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty); + let inner_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap()); let val = CValue::by_ref(Pointer::new(ptr.load_scalar(fx)), inner_layout); ret.write_cvalue(fx, val); } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 67f9d83106294..452b5988dab4c 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -974,7 +974,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( intrinsic_args!(fx, args => (ptr, offset); intrinsic); let (lane_count, ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx); - let pointee_ty = ptr_lane_ty.builtin_deref(true).unwrap().ty; + let pointee_ty = ptr_lane_ty.builtin_deref(true).unwrap(); let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); let ret_lane_layout = fx.layout_of(ret_lane_ty); diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index c9f84b6999718..e72951b6f3447 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -95,7 +95,7 @@ mod prelude { pub(crate) use rustc_middle::mir::{self, *}; pub(crate) use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; pub(crate) use rustc_middle::ty::{ - self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut, UintTy, + self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, UintTy, }; pub(crate) use rustc_span::Span; pub(crate) use rustc_target::abi::{Abi, FieldIdx, Scalar, Size, VariantIdx, FIRST_VARIANT}; diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs index 714858084ec9d..4d96a26ea4fa8 100644 --- a/compiler/rustc_codegen_cranelift/src/num.rs +++ b/compiler/rustc_codegen_cranelift/src/num.rs @@ -388,12 +388,8 @@ pub(crate) fn codegen_ptr_binop<'tcx>( in_lhs: CValue<'tcx>, in_rhs: CValue<'tcx>, ) -> CValue<'tcx> { - let is_thin_ptr = in_lhs - .layout() - .ty - .builtin_deref(true) - .map(|TypeAndMut { ty, mutbl: _ }| !has_ptr_meta(fx.tcx, ty)) - .unwrap_or(true); + let is_thin_ptr = + in_lhs.layout().ty.builtin_deref(true).map(|ty| !has_ptr_meta(fx.tcx, ty)).unwrap_or(true); if is_thin_ptr { match bin_op { @@ -404,7 +400,7 @@ pub(crate) fn codegen_ptr_binop<'tcx>( codegen_compare_bin_op(fx, bin_op, false, lhs, rhs) } BinOp::Offset => { - let pointee_ty = in_lhs.layout().ty.builtin_deref(true).unwrap().ty; + let pointee_ty = in_lhs.layout().ty.builtin_deref(true).unwrap(); let (base, offset) = (in_lhs, in_rhs.load_scalar(fx)); let pointee_size = fx.layout_of(pointee_ty).size.bytes(); let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64); diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index f33bacb99a3fa..4acbc8a27edb9 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -127,7 +127,7 @@ pub(crate) fn coerce_unsized_into<'tcx>( let dst_ty = dst.layout().ty; let mut coerce_ptr = || { let (base, info) = - if fx.layout_of(src.layout().ty.builtin_deref(true).unwrap().ty).is_unsized() { + if fx.layout_of(src.layout().ty.builtin_deref(true).unwrap()).is_unsized() { let (old_base, old_info) = src.load_scalar_pair(fx); unsize_ptr(fx, old_base, src.layout(), dst.layout(), Some(old_info)) } else { diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index dded6df7771df..a11abd0c0e978 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -819,7 +819,7 @@ impl<'tcx> CPlace<'tcx> { } pub(crate) fn place_deref(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> CPlace<'tcx> { - let inner_layout = fx.layout_of(self.layout().ty.builtin_deref(true).unwrap().ty); + let inner_layout = fx.layout_of(self.layout().ty.builtin_deref(true).unwrap()); if has_ptr_meta(fx.tcx, inner_layout.ty) { let (addr, extra) = self.to_cvalue(fx).load_scalar_pair(fx); CPlace::for_ptr_with_extra(Pointer::new(addr), extra, inner_layout) diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 04e24320f9131..14c607ccad7d7 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -59,7 +59,7 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( if let ty::Ref(_, ty, _) = arg.layout().ty.kind() { if ty.is_dyn_star() { - let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap().ty); + let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap()); let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout); let ptr = dyn_star.place_field(fx, FieldIdx::ZERO).to_ptr(); let vtable = diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index 23a5e5ff8730c..4a3b6f678c444 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1301,19 +1301,13 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn memmove( &mut self, dst: RValue<'gcc>, - dst_align: Align, + _dst_align: Align, src: RValue<'gcc>, - src_align: Align, + _src_align: Align, size: RValue<'gcc>, flags: MemFlags, ) { - if flags.contains(MemFlags::NONTEMPORAL) { - // HACK(nox): This is inefficient but there is no nontemporal memmove. - let val = self.load(src.get_type().get_pointee().expect("get_pointee"), src, src_align); - let ptr = self.pointercast(dst, self.type_ptr_to(self.val_ty(val))); - self.store_with_flags(val, ptr, dst_align, flags); - return; - } + assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memmove not supported"); let size = self.intcast(size, self.type_size_t(), false); let _is_volatile = flags.contains(MemFlags::VOLATILE); let dst = self.pointercast(dst, self.type_i8p()); @@ -1335,6 +1329,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { _align: Align, flags: MemFlags, ) { + assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memset not supported"); let _is_volatile = flags.contains(MemFlags::VOLATILE); let ptr = self.pointercast(ptr, self.type_i8p()); let memset = self.context.get_builtin_function("memset"); diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index aed15769025f1..1d0a6d9f09bb9 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -1,10 +1,9 @@ -use crate::rustc_index::Idx; use gccjit::{Location, RValue}; use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind}; use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods}; use rustc_data_structures::sync::Lrc; use rustc_index::bit_set::BitSet; -use rustc_index::IndexVec; +use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::{self, Body, SourceScope}; use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty}; use rustc_session::config::DebugInfo; diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 8f9bfbbd18fb0..2155cabe171c2 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -1,15 +1,15 @@ use std::fmt::Write; -use crate::rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods}; use gccjit::{Struct, Type}; +use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods}; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_target::abi::call::{CastTarget, FnAbi, Reg}; use rustc_target::abi::{ - self, Abi, Align, FieldsShape, Int, Integer, PointeeInfo, Pointer, Size, TyAbiInterface, - Variants, F128, F16, F32, F64, + self, Abi, Align, FieldsShape, Float, Int, Integer, PointeeInfo, Pointer, Size, TyAbiInterface, + Variants, }; use crate::abi::{FnAbiGcc, FnAbiGccExt, GccType}; @@ -205,7 +205,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { /// of that field's type - this is useful for taking the address of /// that field and ensuring the struct has the right alignment. fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { - use crate::rustc_middle::ty::layout::FnAbiOf; + use rustc_middle::ty::layout::FnAbiOf; // This must produce the same result for `repr(transparent)` wrappers as for the inner type! // In other words, this should generally not look at the type at all, but only at the // layout. @@ -283,10 +283,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { match scalar.primitive() { Int(i, true) => cx.type_from_integer(i), Int(i, false) => cx.type_from_unsigned_integer(i), - F16 => cx.type_f16(), - F32 => cx.type_f32(), - F64 => cx.type_f64(), - F128 => cx.type_f128(), + Float(f) => cx.type_from_float(f), Pointer(address_space) => { // If we know the alignment, pick something better than i8. let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) { diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 123aef0f31076..a6a3f0f964611 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -583,7 +583,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { let element_type_index = unsafe { llvm::LLVMRustGetElementTypeArgIndex(callsite) }; if element_type_index >= 0 { let arg_ty = self.args[element_type_index as usize].layout.ty; - let pointee_ty = arg_ty.builtin_deref(true).expect("Must be pointer argument").ty; + let pointee_ty = arg_ty.builtin_deref(true).expect("Must be pointer argument"); let element_type_attr = unsafe { llvm::LLVMRustCreateElementTypeAttr(bx.llcx, bx.layout_of(pointee_ty).llvm_type(bx)) }; diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index e09869cf425c1..71d4343ee07fb 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -904,8 +904,8 @@ fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Ty Primitive::Int(Integer::I16, _) => cx.type_i16(), Primitive::Int(Integer::I32, _) => cx.type_i32(), Primitive::Int(Integer::I64, _) => cx.type_i64(), - Primitive::F32 => cx.type_f32(), - Primitive::F64 => cx.type_f64(), + Primitive::Float(Float::F32) => cx.type_f32(), + Primitive::Float(Float::F64) => cx.type_f64(), // FIXME(erikdesjardins): handle non-default addrspace ptr sizes Primitive::Pointer(_) => cx.type_from_integer(dl.ptr_sized_integer()), _ => unreachable!(), @@ -950,7 +950,7 @@ fn llvm_fixup_input<'ll, 'tcx>( bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices)) } (InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) - if s.primitive() == Primitive::F64 => + if s.primitive() == Primitive::Float(Float::F64) => { bx.bitcast(value, bx.cx.type_i64()) } @@ -986,8 +986,8 @@ fn llvm_fixup_input<'ll, 'tcx>( match s.primitive() { // MIPS only supports register-length arithmetics. Primitive::Int(Integer::I8 | Integer::I16, _) => bx.zext(value, bx.cx.type_i32()), - Primitive::F32 => bx.bitcast(value, bx.cx.type_i32()), - Primitive::F64 => bx.bitcast(value, bx.cx.type_i64()), + Primitive::Float(Float::F32) => bx.bitcast(value, bx.cx.type_i32()), + Primitive::Float(Float::F64) => bx.bitcast(value, bx.cx.type_i64()), _ => value, } } @@ -1027,7 +1027,7 @@ fn llvm_fixup_output<'ll, 'tcx>( bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices)) } (InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) - if s.primitive() == Primitive::F64 => + if s.primitive() == Primitive::Float(Float::F64) => { bx.bitcast(value, bx.cx.type_f64()) } @@ -1064,8 +1064,8 @@ fn llvm_fixup_output<'ll, 'tcx>( // MIPS only supports register-length arithmetics. Primitive::Int(Integer::I8, _) => bx.trunc(value, bx.cx.type_i8()), Primitive::Int(Integer::I16, _) => bx.trunc(value, bx.cx.type_i16()), - Primitive::F32 => bx.bitcast(value, bx.cx.type_f32()), - Primitive::F64 => bx.bitcast(value, bx.cx.type_f64()), + Primitive::Float(Float::F32) => bx.bitcast(value, bx.cx.type_f32()), + Primitive::Float(Float::F64) => bx.bitcast(value, bx.cx.type_f64()), _ => value, } } @@ -1100,7 +1100,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( cx.type_vector(elem_ty, count * 2) } (InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s)) - if s.primitive() == Primitive::F64 => + if s.primitive() == Primitive::Float(Float::F64) => { cx.type_i64() } @@ -1136,8 +1136,8 @@ fn llvm_fixup_output_type<'ll, 'tcx>( match s.primitive() { // MIPS only supports register-length arithmetics. Primitive::Int(Integer::I8 | Integer::I16, _) => cx.type_i32(), - Primitive::F32 => cx.type_i32(), - Primitive::F64 => cx.type_i64(), + Primitive::Float(Float::F32) => cx.type_i32(), + Primitive::Float(Float::F64) => cx.type_i64(), _ => layout.llvm_type(cx), } } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 1a1b4ae383133..230c58dfcafb7 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -576,7 +576,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } } } - abi::F16 | abi::F32 | abi::F64 | abi::F128 => {} + abi::Float(_) => {} } } @@ -976,6 +976,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { align: Align, flags: MemFlags, ) { + assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memset not supported"); let is_volatile = flags.contains(MemFlags::VOLATILE); unsafe { llvm::LLVMRustBuildMemSet( diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 653abb4e41b3d..53a098d178e41 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -133,6 +133,15 @@ pub unsafe fn create_module<'ll>( } } + if llvm_version < (19, 0, 0) { + if sess.target.arch == "aarch64" || sess.target.arch.starts_with("arm64") { + // LLVM 19 sets -Fn32 in its data layout string for 64-bit ARM + // Earlier LLVMs leave this default, so remove it. + // See https://github.com/llvm/llvm-project/pull/90702 + target_data_layout = target_data_layout.replace("-Fn32", ""); + } + } + // Ensure the data-layout values hardcoded remain the defaults. { let tm = crate::back::write::create_informational_target_machine(tcx.sess); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index e5fecddec528d..f44738ba6421f 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1281,7 +1281,7 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>( let mut names = generics .parent .map_or_else(Vec::new, |def_id| get_parameter_names(cx, cx.tcx.generics_of(def_id))); - names.extend(generics.params.iter().map(|param| param.name)); + names.extend(generics.own_params.iter().map(|param| param.name)); names } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index 657e9ce998f93..bacd74f430f73 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -122,10 +122,7 @@ fn tag_base_type<'ll, 'tcx>( // Niche tags are always normalized to unsized integers of the correct size. match tag.primitive() { Primitive::Int(t, _) => t, - Primitive::F16 => Integer::I16, - Primitive::F32 => Integer::I32, - Primitive::F64 => Integer::I64, - Primitive::F128 => Integer::I128, + Primitive::Float(f) => Integer::from_size(f.size()).unwrap(), // FIXME(erikdesjardins): handle non-default addrspace ptr sizes Primitive::Pointer(_) => { // If the niche is the NULL value of a reference, then `discr_enum_ty` will be diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 4fdaa59e0e559..6149c18696cf2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -512,7 +512,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let mut names = generics.parent.map_or_else(Vec::new, |def_id| { get_parameter_names(cx, cx.tcx.generics_of(def_id)) }); - names.extend(generics.params.iter().map(|param| param.name)); + names.extend(generics.own_params.iter().map(|param| param.name)); names } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 56550dbfa4b8b..b0b867701a43e 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf}; use rustc_middle::ty::{self, GenericArgsRef, Ty}; use rustc_middle::{bug, span_bug}; use rustc_span::{sym, Span, Symbol}; -use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size}; +use rustc_target::abi::{self, Align, Float, HasDataLayout, Primitive, Size}; use rustc_target::spec::{HasTargetSpec, PanicStrategy}; use std::cmp::Ordering; @@ -231,13 +231,17 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> { emit_va_arg(self, args[0], ret_ty) } } - Primitive::F16 => bug!("the va_arg intrinsic does not work with `f16`"), - Primitive::F64 | Primitive::Pointer(_) => { + Primitive::Float(Float::F16) => { + bug!("the va_arg intrinsic does not work with `f16`") + } + Primitive::Float(Float::F64) | Primitive::Pointer(_) => { emit_va_arg(self, args[0], ret_ty) } // `va_arg` should never be used with the return type f32. - Primitive::F32 => bug!("the va_arg intrinsic does not work with `f32`"), - Primitive::F128 => { + Primitive::Float(Float::F32) => { + bug!("the va_arg intrinsic does not work with `f32`") + } + Primitive::Float(Float::F128) => { bug!("the va_arg intrinsic does not work with `f128`") } } @@ -2383,7 +2387,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( let pointee = in_elem.builtin_deref(true).unwrap_or_else(|| { span_bug!(span, "must be called with a vector of pointer types as first argument") }); - let layout = bx.layout_of(pointee.ty); + let layout = bx.layout_of(pointee); let ptrs = args[0].immediate(); // The second argument must be a ptr-sized integer. // (We don't care about the signedness, this is wrapping anyway.) diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 40ed6baa61072..5f60fd23a5fe9 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -6,7 +6,7 @@ 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::{Abi, Align, FieldsShape}; -use rustc_target::abi::{Int, Pointer, F128, F16, F32, F64}; +use rustc_target::abi::{Float, Int, Pointer}; use rustc_target::abi::{Scalar, Size, Variants}; use std::fmt::Write; @@ -272,10 +272,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, scalar: Scalar) -> &'a Type { match scalar.primitive() { Int(i, _) => cx.type_from_integer(i), - F16 => cx.type_f16(), - F32 => cx.type_f32(), - F64 => cx.type_f64(), - F128 => cx.type_f128(), + Float(f) => cx.type_from_float(f), Pointer(address_space) => cx.type_ptr_ext(address_space), } } diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index f347a7fb0bb10..3771fc6b0a271 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -6,8 +6,10 @@ edition = "2021" [dependencies] # tidy-alphabetical-start ar_archive_writer = "0.2.0" +arrayvec = { version = "0.7", default-features = false } bitflags = "2.4.1" cc = "1.0.90" +either = "1.5.0" itertools = "0.12" jobserver = "0.1.28" pathdiff = "0.2.0" diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 1f691d14c5320..6939674ce9dd7 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3127,7 +3127,13 @@ fn add_lld_args( // 2. Implement the "linker flavor" part of this feature by asking `cc` to use some kind of // `lld` as the linker. - cmd.arg("-fuse-ld=lld"); + // + // Note that wasm targets skip this step since the only option there anyway + // is to use LLD but the `wasm32-wasip2` target relies on a wrapper around + // this, `wasm-component-ld`, which is overridden if this option is passed. + if !sess.target.is_like_wasm { + cmd.arg("-fuse-ld=lld"); + } if !flavor.is_gnu() { // Tell clang to use a non-default LLD flavor. diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 358c24bfb823c..877e5b75912ea 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -283,7 +283,7 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } if src_f.layout.ty == dst_f.layout.ty { - bx.typed_place_copy(dst_f, src_f); + bx.typed_place_copy(dst_f.val, src_f.val, src_f.layout); } else { coerce_unsized_into(bx, src_f, dst_f); } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 2f57695ac290e..ba6aad51316cb 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -1060,7 +1060,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Make sure that we've actually unwrapped the rcvr down // to a pointer or ref to `dyn* Trait`. - if !op.layout.ty.builtin_deref(true).unwrap().ty.is_dyn_star() { + if !op.layout.ty.builtin_deref(true).unwrap().is_dyn_star() { span_bug!(span, "can't codegen a virtual call on {:#?}", op); } let place = op.deref(bx.cx()); @@ -1454,9 +1454,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Some(pointee_align) => cmp::max(pointee_align, arg.layout.align.abi), None => arg.layout.align.abi, }; - let scratch = PlaceRef::alloca_aligned(bx, arg.layout, required_align); - op.val.store(bx, scratch); - (scratch.val.llval, scratch.val.align, true) + let scratch = PlaceValue::alloca(bx, arg.layout.size, required_align); + op.val.store(bx, scratch.with_type(arg.layout)); + (scratch.llval, scratch.align, true) } PassMode::Cast { .. } => { let scratch = PlaceRef::alloca(bx, arg.layout); @@ -1475,10 +1475,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // 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); - 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) + let scratch = PlaceValue::alloca(bx, arg.layout.size, required_align); + bx.typed_place_copy(scratch, op_place_val, op.layout); + (scratch.llval, scratch.align, true) } else { (op_place_val.llval, op_place_val.align, true) } @@ -1567,7 +1566,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if place_val.llextra.is_some() { bug!("closure arguments must be sized"); } - let tuple_ptr = PlaceRef { val: place_val, layout: tuple.layout }; + let tuple_ptr = place_val.with_type(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); diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 50bf1ef61f3a4..6b89636b6540c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -120,7 +120,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx> { fn deref(&self, bx: &mut Bx) -> Self { bx.cx().layout_of( - self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)).ty, + self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)), ) } diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 2e008460798f8..f88deaa7abca6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -1,4 +1,4 @@ -use super::operand::{OperandRef, OperandValue}; +use super::operand::OperandRef; use super::place::PlaceRef; use super::FunctionCx; use crate::errors; @@ -93,9 +93,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // into the (unoptimized) direct swapping implementation, so we disable it. || bx.sess().target.arch == "spirv" { - let x_place = PlaceRef::new_sized(args[0].immediate(), pointee_layout); - let y_place = PlaceRef::new_sized(args[1].immediate(), pointee_layout); - bx.typed_place_swap(x_place, y_place); + let align = pointee_layout.align.abi; + let x_place = args[0].val.deref(align); + let y_place = args[1].val.deref(align); + bx.typed_place_swap(x_place, y_place, pointee_layout); return Ok(()); } } @@ -113,15 +114,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { sym::va_end => bx.va_end(args[0].immediate()), sym::size_of_val => { let tp_ty = fn_args.type_at(0); - let meta = - if let OperandValue::Pair(_, meta) = args[0].val { Some(meta) } else { None }; + let (_, meta) = args[0].val.pointer_parts(); let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta); llsize } sym::min_align_of_val => { let tp_ty = fn_args.type_at(0); - let meta = - if let OperandValue::Pair(_, meta) = args[0].val { Some(meta) } else { None }; + let (_, meta) = args[0].val.pointer_parts(); let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta); llalign } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 38f77f2e646fc..e1c584e8ed5f1 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -14,6 +14,9 @@ use rustc_target::abi::{self, Abi, Align, Size}; use std::fmt; +use arrayvec::ArrayVec; +use either::Either; + /// The representation of a Rust value. The enum variant is in fact /// uniquely determined by the value's type, but is kept as a /// safety check. @@ -58,6 +61,57 @@ pub enum OperandValue { ZeroSized, } +impl OperandValue { + /// If this is ZeroSized/Immediate/Pair, return an array of the 0/1/2 values. + /// If this is Ref, return the place. + #[inline] + pub fn immediates_or_place(self) -> Either, PlaceValue> { + match self { + OperandValue::ZeroSized => Either::Left(ArrayVec::new()), + OperandValue::Immediate(a) => Either::Left(ArrayVec::from_iter([a])), + OperandValue::Pair(a, b) => Either::Left([a, b].into()), + OperandValue::Ref(p) => Either::Right(p), + } + } + + /// Given an array of 0/1/2 immediate values, return ZeroSized/Immediate/Pair. + #[inline] + pub fn from_immediates(immediates: ArrayVec) -> Self { + let mut it = immediates.into_iter(); + let Some(a) = it.next() else { + return OperandValue::ZeroSized; + }; + let Some(b) = it.next() else { + return OperandValue::Immediate(a); + }; + OperandValue::Pair(a, b) + } + + /// Treat this value as a pointer and return the data pointer and + /// optional metadata as backend values. + /// + /// If you're making a place, use [`Self::deref`] instead. + pub fn pointer_parts(self) -> (V, Option) { + match self { + OperandValue::Immediate(llptr) => (llptr, None), + OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)), + _ => bug!("OperandValue cannot be a pointer: {self:?}"), + } + } + + /// Treat this value as a pointer and return the place to which it points. + /// + /// The pointer immediate doesn't inherently know its alignment, + /// so you need to pass it in. If you want to get it from a type's ABI + /// alignment, then maybe you want [`OperandRef::deref`] instead. + /// + /// This is the inverse of [`PlaceValue::address`]. + pub fn deref(self, align: Align) -> PlaceValue { + let (llval, llextra) = self.pointer_parts(); + PlaceValue { llval, llextra, align } + } +} + /// An `OperandRef` is an "SSA" reference to a Rust value, along with /// its type. /// @@ -205,6 +259,15 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } } + /// Asserts that this operand is a pointer (or reference) and returns + /// the place to which it points. (This requires no code to be emitted + /// as we represent places using the pointer to the place.) + /// + /// This uses [`Ty::builtin_deref`] to include the type of the place and + /// assumes the place is aligned to the pointee's usual ABI alignment. + /// + /// If you don't need the type, see [`OperandValue::pointer_parts`] + /// or [`OperandValue::deref`]. pub fn deref>(self, cx: &Cx) -> PlaceRef<'tcx, V> { if self.layout.ty.is_box() { // Derefer should have removed all Box derefs @@ -215,18 +278,10 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { .layout .ty .builtin_deref(true) - .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)) - .ty; + .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)); - let (llptr, llextra) = match self.val { - OperandValue::Immediate(llptr) => (llptr, None), - OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)), - OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self), - OperandValue::ZeroSized => bug!("Deref of ZST operand {:?}", self), - }; let layout = cx.layout_of(projected_ty); - let val = PlaceValue { llval: llptr, llextra, align: layout.align.abi }; - PlaceRef { val, layout } + self.val.deref(layout.align.abi).with_type(layout) } /// If this operand is a `Pair`, we return an aggregate with the two values. @@ -419,8 +474,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { if val.llextra.is_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); + bx.typed_place_copy_with_flags(dest.val, val, dest.layout, flags); } OperandValue::Immediate(s) => { let val = bx.from_immediate(s); @@ -455,8 +509,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { .layout .ty .builtin_deref(true) - .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest)) - .ty; + .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest)); let OperandValue::Ref(PlaceValue { llval: llptr, llextra: Some(llextra), .. }) = self else { diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 870a105c61d6f..971ac2defdc0d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -10,12 +10,15 @@ use rustc_middle::mir; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty}; -use rustc_target::abi::{Align, FieldsShape, Int, Pointer, TagEncoding}; +use rustc_target::abi::{Align, FieldsShape, Int, Pointer, Size, 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`]. +/// +/// As a location in memory, this has no specific type. If you want to +/// load or store it using a typed operation, use [`Self::with_type`]. #[derive(Copy, Clone, Debug)] pub struct PlaceValue { /// A pointer to the contents of the place. @@ -35,6 +38,41 @@ impl PlaceValue { pub fn new_sized(llval: V, align: Align) -> PlaceValue { PlaceValue { llval, llextra: None, align } } + + /// Allocates a stack slot in the function for a value + /// of the specified size and alignment. + /// + /// The allocation itself is untyped. + pub fn alloca<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx, Value = V>>( + bx: &mut Bx, + size: Size, + align: Align, + ) -> PlaceValue { + let llval = bx.alloca(size, align); + PlaceValue::new_sized(llval, align) + } + + /// Creates a `PlaceRef` to this location with the given type. + pub fn with_type<'tcx>(self, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> { + debug_assert!( + layout.is_unsized() || layout.abi.is_uninhabited() || self.llextra.is_none(), + "Had pointer metadata {:?} for sized type {layout:?}", + self.llextra, + ); + PlaceRef { val: self, layout } + } + + /// Gets the pointer to this place as an [`OperandValue::Immediate`] + /// or, for those needing metadata, an [`OperandValue::Pair`]. + /// + /// This is the inverse of [`OperandValue::deref`]. + pub fn address(self) -> OperandValue { + if let Some(llextra) = self.llextra { + OperandValue::Pair(self.llval, llextra) + } else { + OperandValue::Immediate(self.llval) + } + } } #[derive(Copy, Clone, Debug)] @@ -52,9 +90,7 @@ pub struct PlaceRef<'tcx, V> { impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { pub fn new_sized(llval: V, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> { - assert!(layout.is_sized()); - let val = PlaceValue::new_sized(llval, layout.align.abi); - PlaceRef { val, layout } + PlaceRef::new_sized_aligned(llval, layout, layout.align.abi) } pub fn new_sized_aligned( @@ -63,8 +99,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { align: Align, ) -> PlaceRef<'tcx, V> { assert!(layout.is_sized()); - let val = PlaceValue::new_sized(llval, align); - PlaceRef { val, layout } + PlaceValue::new_sized(llval, align).with_type(layout) } // FIXME(eddyb) pass something else for the name so no work is done @@ -72,18 +107,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { pub fn alloca>( bx: &mut Bx, layout: TyAndLayout<'tcx>, - ) -> Self { - Self::alloca_aligned(bx, layout, layout.align.abi) - } - - pub fn alloca_aligned>( - bx: &mut Bx, - layout: TyAndLayout<'tcx>, - align: Align, ) -> Self { assert!(layout.is_sized(), "tried to statically allocate unsized place"); - let tmp = bx.alloca(layout.size, align); - Self::new_sized_aligned(tmp, layout, align) + PlaceValue::alloca(bx, layout.size, layout.align.abi).with_type(layout) } /// Returns a place for an indirect reference to an unsized place. @@ -132,18 +158,12 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { } else { bx.inbounds_ptradd(self.val.llval, bx.const_usize(offset.bytes())) }; - PlaceRef { - val: PlaceValue { + let val = PlaceValue { llval, - llextra: if bx.cx().type_has_metadata(field.ty) { - self.val.llextra - } else { - None - }, + llextra: if bx.cx().type_has_metadata(field.ty) { self.val.llextra } else { None }, align: effective_field_align, - }, - layout: field, - } + }; + val.with_type(field) }; // Simple cases, which don't need DST adjustment: @@ -198,7 +218,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { 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 } + val.with_type(field) } /// Obtain the actual discriminant of a value. @@ -387,18 +407,13 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { layout.size }; - PlaceRef { - val: PlaceValue { - llval: bx.inbounds_gep( + let 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, - } + ); + let align = self.val.align.restrict_for_offset(offset); + PlaceValue::new_sized(llval, align).with_type(layout) } pub fn project_downcast>( diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 4e7d251a2e928..e47a8198736f2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -8,14 +8,16 @@ use crate::traits::*; use crate::MemFlags; use rustc_hir as hir; -use rustc_middle::mir::{self, AggregateKind, Operand}; +use rustc_middle::mir; use rustc_middle::ty::cast::{CastTy, IntTy}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::config::OptLevel; use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi::{self, FIRST_VARIANT}; +use rustc_target::abi::{self, FieldIdx, FIRST_VARIANT}; + +use arrayvec::ArrayVec; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { #[instrument(level = "trace", skip(self, bx))] @@ -72,8 +74,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { 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); + base::coerce_unsized_into(bx, val.with_type(operand.layout), dest); } OperandValue::ZeroSized => { bug!("unsized coercion on a ZST rvalue"); @@ -182,10 +183,7 @@ 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.val.llval, src.layout, dst.val.align), - ); + src.val.store(bx, dst.val.with_type(src.layout)); } } } @@ -223,8 +221,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { OperandValue::Ref(source_place_val) => { debug_assert_eq!(source_place_val.llextra, None); debug_assert!(matches!(operand_kind, OperandValueKind::Ref)); - let fake_place = PlaceRef { val: source_place_val, layout: cast }; - Some(bx.load_operand(fake_place).val) + Some(bx.load_operand(source_place_val.with_type(cast)).val) } OperandValue::ZeroSized => { let OperandValueKind::ZeroSized = operand_kind else { @@ -306,17 +303,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty); imm = match (from_scalar.primitive(), to_scalar.primitive()) { - (Int(..) | F16 | F32 | F64 | F128, Int(..) | F16 | F32 | F64 | F128) => { - bx.bitcast(imm, to_backend_ty) - } + (Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty), (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty), (Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm), (Pointer(..), Int(..)) => bx.ptrtoint(imm, to_backend_ty), - (F16 | F32 | F64 | F128, Pointer(..)) => { + (Float(_), Pointer(..)) => { let int_imm = bx.bitcast(imm, bx.cx().type_isize()); bx.ptradd(bx.const_null(bx.type_ptr()), int_imm) } - (Pointer(..), F16 | F32 | F64 | F128) => { + (Pointer(..), Float(_)) => { let int_imm = bx.ptrtoint(imm, bx.cx().type_isize()); bx.bitcast(int_imm, to_backend_ty) } @@ -452,23 +447,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::CastKind::PointerCoercion(PointerCoercion::Unsize) => { assert!(bx.cx().is_backend_scalar_pair(cast)); - let (lldata, llextra) = match operand.val { - OperandValue::Pair(lldata, llextra) => { - // unsize from a fat pointer -- this is a - // "trait-object-to-supertrait" coercion. - (lldata, Some(llextra)) - } - OperandValue::Immediate(lldata) => { - // "standard" unsize - (lldata, None) - } - OperandValue::Ref(..) => { - bug!("by-ref operand {:?} in `codegen_rvalue_operand`", operand); - } - OperandValue::ZeroSized => { - bug!("zero-sized operand {:?} in `codegen_rvalue_operand`", operand); - } - }; + let (lldata, llextra) = operand.val.pointer_parts(); let (lldata, llextra) = base::unsize_ptr(bx, lldata, operand.layout.ty, cast.ty, llextra); OperandValue::Pair(lldata, llextra) @@ -489,12 +468,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::Immediate(v) => (v, None), - OperandValue::Pair(v, l) => (v, Some(l)), - OperandValue::ZeroSized => bug!("ZST -- which is not PointerLike -- in DynStar"), - }; + let (lldata, llextra) = operand.val.pointer_parts(); let (lldata, llextra) = base::cast_to_dyn_star(bx, lldata, operand.layout, cast.ty, llextra); OperandValue::Pair(lldata, llextra) @@ -581,7 +555,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_place_to_pointer(bx, place, mk_ref) } - mir::Rvalue::CopyForDeref(place) => self.codegen_operand(bx, &Operand::Copy(place)), + mir::Rvalue::CopyForDeref(place) => { + self.codegen_operand(bx, &mir::Operand::Copy(place)) + } mir::Rvalue::AddressOf(mutability, place) => { let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| Ty::new_ptr(tcx, ty, mutability); @@ -738,11 +714,41 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { _ => bug!("RawPtr operands {data:?} {meta:?}"), } } - mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) => { - // According to `rvalue_creates_operand`, only ZST - // aggregate rvalues are allowed to be operands. + mir::Rvalue::Repeat(..) => bug!("{rvalue:?} in codegen_rvalue_operand"), + mir::Rvalue::Aggregate(_, ref fields) => { let ty = rvalue.ty(self.mir, self.cx.tcx()); - OperandRef::zero_sized(self.cx.layout_of(self.monomorphize(ty))) + let ty = self.monomorphize(ty); + let layout = self.cx.layout_of(ty); + + // `rvalue_creates_operand` has arranged that we only get here if + // we can build the aggregate immediate from the field immediates. + let mut inputs = ArrayVec::::new(); + let mut input_scalars = ArrayVec::::new(); + for field_idx in layout.fields.index_by_increasing_offset() { + let field_idx = FieldIdx::from_usize(field_idx); + let op = self.codegen_operand(bx, &fields[field_idx]); + let values = op.val.immediates_or_place().left_or_else(|p| { + bug!("Field {field_idx:?} is {p:?} making {layout:?}"); + }); + inputs.extend(values); + let scalars = self.value_kind(op.layout).scalars().unwrap(); + input_scalars.extend(scalars); + } + + let output_scalars = self.value_kind(layout).scalars().unwrap(); + itertools::izip!(&mut inputs, input_scalars, output_scalars).for_each( + |(v, in_s, out_s)| { + if in_s != out_s { + // We have to be really careful about bool here, because + // `(bool,)` stays i1 but `Cell` becomes i8. + *v = bx.from_immediate(*v); + *v = bx.to_immediate_scalar(*v, out_s); + } + }, + ); + + let val = OperandValue::from_immediates(inputs); + OperandRef { val, layout } } mir::Rvalue::ShallowInitBox(ref operand, content_ty) => { let operand = self.codegen_operand(bx, operand); @@ -780,16 +786,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mk_ptr_ty: impl FnOnce(TyCtxt<'tcx>, Ty<'tcx>) -> Ty<'tcx>, ) -> OperandRef<'tcx, Bx::Value> { let cg_place = self.codegen_place(bx, place.as_ref()); + let val = cg_place.val.address(); let ty = cg_place.layout.ty; - - // 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.val.llval) + debug_assert!( + if bx.cx().type_has_metadata(ty) { + matches!(val, OperandValue::Pair(..)) } else { - OperandValue::Pair(cg_place.val.llval, cg_place.val.llextra.unwrap()) - }; + matches!(val, OperandValue::Immediate(..)) + }, + "Address of place was unexpectedly {val:?} for pointee type {ty:?}", + ); + OperandRef { val, layout: self.cx.layout_of(mk_ptr_ty(self.cx.tcx(), ty)) } } @@ -870,8 +878,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::BinOp::Offset => { let pointee_type = input_ty .builtin_deref(true) - .unwrap_or_else(|| bug!("deref of non-pointer {:?}", input_ty)) - .ty; + .unwrap_or_else(|| bug!("deref of non-pointer {:?}", input_ty)); let pointee_layout = bx.cx().layout_of(pointee_type); if pointee_layout.is_zst() { // `Offset` works in terms of the size of pointee, @@ -1050,14 +1057,29 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::ThreadLocalRef(_) | mir::Rvalue::Use(..) => // (*) true, - // This always produces a `ty::RawPtr`, so will be Immediate or Pair - mir::Rvalue::Aggregate(box AggregateKind::RawPtr(..), ..) => true, - mir::Rvalue::Repeat(..) | - mir::Rvalue::Aggregate(..) => { + // Arrays are always aggregates, so it's not worth checking anything here. + // (If it's really `[(); N]` or `[T; 0]` and we use the place path, fine.) + mir::Rvalue::Repeat(..) => false, + mir::Rvalue::Aggregate(ref kind, _) => { + let allowed_kind = match **kind { + // This always produces a `ty::RawPtr`, so will be Immediate or Pair + mir::AggregateKind::RawPtr(..) => true, + mir::AggregateKind::Array(..) => false, + mir::AggregateKind::Tuple => true, + mir::AggregateKind::Adt(def_id, ..) => { + let adt_def = self.cx.tcx().adt_def(def_id); + adt_def.is_struct() && !adt_def.repr().simd() + } + mir::AggregateKind::Closure(..) => true, + // FIXME: Can we do this for simple coroutines too? + mir::AggregateKind::Coroutine(..) | mir::AggregateKind::CoroutineClosure(..) => false, + }; + allowed_kind && { let ty = rvalue.ty(self.mir, self.cx.tcx()); let ty = self.monomorphize(ty); - // For ZST this can be `OperandValueKind::ZeroSized`. - self.cx.spanned_layout_of(ty, span).is_zst() + let layout = self.cx.spanned_layout_of(ty, span); + !self.cx.is_backend_ref(layout) + } } } @@ -1099,3 +1121,14 @@ enum OperandValueKind { Pair(abi::Scalar, abi::Scalar), ZeroSized, } + +impl OperandValueKind { + fn scalars(self) -> Option> { + Some(match self { + OperandValueKind::ZeroSized => ArrayVec::new(), + OperandValueKind::Immediate(a) => ArrayVec::from_iter([a]), + OperandValueKind::Pair(a, b) => [a, b].into(), + OperandValueKind::Ref => return None, + }) + } +} diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 51b22bfaf2558..fdeccb9070082 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -186,6 +186,15 @@ pub trait BuilderMethods<'a, 'tcx>: align: Align, flags: MemFlags, ) -> Self::Value; + fn store_to_place_with_flags( + &mut self, + val: Self::Value, + place: PlaceValue, + flags: MemFlags, + ) -> Self::Value { + debug_assert_eq!(place.llextra, None); + self.store_with_flags(val, place.llval, place.align, flags) + } fn atomic_store( &mut self, val: Self::Value, @@ -286,35 +295,36 @@ pub trait BuilderMethods<'a, 'tcx>: /// (For example, typed load-stores with alias metadata.) fn typed_place_copy( &mut self, - dst: PlaceRef<'tcx, Self::Value>, - src: PlaceRef<'tcx, Self::Value>, + dst: PlaceValue, + src: PlaceValue, + layout: TyAndLayout<'tcx>, ) { - self.typed_place_copy_with_flags(dst, src, MemFlags::empty()); + self.typed_place_copy_with_flags(dst, src, layout, MemFlags::empty()); } fn typed_place_copy_with_flags( &mut self, - dst: PlaceRef<'tcx, Self::Value>, - src: PlaceRef<'tcx, Self::Value>, + dst: PlaceValue, + src: PlaceValue, + layout: TyAndLayout<'tcx>, 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); + debug_assert!(layout.is_sized(), "cannot typed-copy an unsigned type"); + debug_assert!(src.llextra.is_none(), "cannot directly copy from unsized values"); + debug_assert!(dst.llextra.is_none(), "cannot directly copy into unsized values"); 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) - { + let ty = self.backend_type(layout); + let val = self.load_from_place(ty, src); + self.store_to_place_with_flags(val, dst, flags); + } else if self.sess().opts.optimize == OptLevel::No && self.is_backend_immediate(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_with_flags(self, dst, flags); - } else if !dst.layout.is_zst() { - let bytes = self.const_usize(dst.layout.size.bytes()); - self.memcpy(dst.val.llval, dst.val.align, src.val.llval, src.val.align, bytes, flags); + let temp = self.load_operand(src.with_type(layout)); + temp.val.store_with_flags(self, dst.with_type(layout), flags); + } else if !layout.is_zst() { + let bytes = self.const_usize(layout.size.bytes()); + self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags); } } @@ -327,18 +337,19 @@ pub trait BuilderMethods<'a, 'tcx>: /// cases (in non-debug), preferring the fallback body instead. fn typed_place_swap( &mut self, - left: PlaceRef<'tcx, Self::Value>, - right: PlaceRef<'tcx, Self::Value>, + left: PlaceValue, + right: PlaceValue, + layout: TyAndLayout<'tcx>, ) { - let mut temp = self.load_operand(left); + let mut temp = self.load_operand(left.with_type(layout)); if let OperandValue::Ref(..) = temp.val { // The SSA value isn't stand-alone, so we need to copy it elsewhere - let alloca = PlaceRef::alloca(self, left.layout); - self.typed_place_copy(alloca, left); + let alloca = PlaceRef::alloca(self, layout); + self.typed_place_copy(alloca.val, left, layout); temp = self.load_operand(alloca); } - self.typed_place_copy(left, right); - temp.val.store(self, right); + self.typed_place_copy(left, right, layout); + temp.val.store(self, right.with_type(layout)); } fn select( diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index ccb35629a829d..403f6a7327715 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -7,7 +7,7 @@ use rustc_middle::bug; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, Ty}; use rustc_target::abi::call::{ArgAbi, CastTarget, FnAbi, Reg}; -use rustc_target::abi::{AddressSpace, Integer}; +use rustc_target::abi::{AddressSpace, Float, Integer}; // This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use // `LayoutOf` or `HasTyCtxt`. This way, they don't have to add a constraint on it themselves. @@ -65,6 +65,16 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { } } + fn type_from_float(&self, f: Float) -> Self::Type { + use Float::*; + match f { + F16 => self.type_f16(), + F32 => self.type_f32(), + F64 => self.type_f64(), + F128 => self.type_f128(), + } + } + fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { ty.needs_drop(self.tcx(), ty::ParamEnv::reveal_all()) } diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index b79d7441acac7..20f0f27517ffe 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -69,9 +69,6 @@ const_eval_deref_function_pointer = accessing {$allocation} which contains a function const_eval_deref_vtable_pointer = accessing {$allocation} which contains a vtable -const_eval_different_allocations = - `{$name}` called on pointers into different allocations - const_eval_division_by_zero = dividing by zero const_eval_division_overflow = @@ -234,12 +231,18 @@ const_eval_not_enough_caller_args = const_eval_nullary_intrinsic_fail = could not evaluate nullary intrinsic +const_eval_offset_from_different_allocations = + `{$name}` called on pointers into different allocations +const_eval_offset_from_different_integers = + `{$name}` called on different pointers without provenance (i.e., without an associated allocation) const_eval_offset_from_overflow = `{$name}` called when first pointer is too far ahead of second - -const_eval_offset_from_test = out-of-bounds `offset_from` +const_eval_offset_from_test = + out-of-bounds `offset_from` const_eval_offset_from_underflow = `{$name}` called when first pointer is too far before second +const_eval_offset_from_unsigned_overflow = + `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: {$a_offset} < {$b_offset} const_eval_operator_non_const = cannot call non-const operator in {const_eval_const_context}s @@ -381,8 +384,6 @@ const_eval_unreachable = entering unreachable code const_eval_unreachable_unwind = unwinding past a stack frame that does not allow unwinding -const_eval_unsigned_offset_from_overflow = - `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: {$a_offset} < {$b_offset} const_eval_unsized_local = unsized locals are not supported const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 763344207c467..2c9eb393e4a14 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -7,7 +7,7 @@ use rustc_middle::mir::AssertKind; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{layout::LayoutError, ConstInt}; -use rustc_span::{Span, Symbol, DUMMY_SP}; +use rustc_span::{Span, Symbol}; use super::CompileTimeInterpreter; use crate::errors::{self, FrameNote, ReportErrorExt}; @@ -121,7 +121,7 @@ where pub(super) fn report<'tcx, C, F, E>( tcx: TyCtxt<'tcx>, error: InterpError<'tcx>, - span: Option, + span: Span, get_span_and_frames: C, mk: F, ) -> ErrorHandled @@ -135,16 +135,16 @@ where // Don't emit a new diagnostic for these errors, they are already reported elsewhere or // should remain silent. err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => { - ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP)) + ErrorHandled::TooGeneric(span) } - err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span.unwrap_or(DUMMY_SP)), + err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span), err_inval!(Layout(LayoutError::ReferencesError(guar))) => { - ErrorHandled::Reported(guar.into(), span.unwrap_or(DUMMY_SP)) + ErrorHandled::Reported(guar.into(), span) } // Report remaining errors. _ => { let (our_span, frames) = get_span_and_frames(); - let span = span.unwrap_or(our_span); + let span = span.substitute_dummy(our_span); let err = mk(span, frames); let mut err = tcx.dcx().create_err(err); diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 40afd9f162f4e..d9f329c8b0e0f 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -12,7 +12,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{self, Abi}; use super::{CanAccessMutGlobal, CompileTimeEvalContext, CompileTimeInterpreter}; @@ -222,7 +222,7 @@ pub(super) fn op_to_const<'tcx>( // This codepath solely exists for `valtree_to_const_value` to not need to generate // a `ConstValue::Indirect` for wide references, so it is tightly restricted to just // that case. - let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap().ty; // `false` = no raw ptrs + let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs debug_assert!( matches!( ecx.tcx.struct_tail_without_normalization(pointee_ty).kind(), @@ -298,7 +298,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>( super::report( tcx, error.into_kind(), - Some(span), + span, || (span, vec![]), |span, _| errors::NullaryIntrinsicError { span }, ) @@ -406,7 +406,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( super::report( *ecx.tcx, error, - None, + DUMMY_SP, || super::get_span_and_frames(ecx.tcx, ecx.stack()), |span, frames| ConstEvalError { span, error_kind: kind, instance, frame_notes: frames }, ) @@ -461,7 +461,7 @@ fn report_validation_error<'mir, 'tcx>( crate::const_eval::report( *ecx.tcx, error, - None, + DUMMY_SP, || crate::const_eval::get_span_and_frames(ecx.tcx, ecx.stack()), move |span, frames| errors::ValidationFailure { span, ub_note, frames, raw_bytes }, ) diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 88ce5a7cbebba..52c31629d547c 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -8,21 +8,16 @@ use rustc_middle::ty::layout::{LayoutOf as _, ValidityRequirement}; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_middle::{ - mir::{ - self, - interpret::{ - Allocation, ConstAllocation, GlobalId, InterpResult, PointerArithmetic, Scalar, - }, - BinOp, ConstValue, NonDivergingIntrinsic, - }, + mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}, ty::layout::TyAndLayout, }; use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::Size; use super::{ - memory::MemoryKind, util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, - MPlaceTy, Machine, OpTy, Pointer, + memory::MemoryKind, util::ensure_monomorphic_enough, Allocation, CheckInAllocMsg, + ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, Pointer, + PointerArithmetic, Scalar, }; use crate::fluent_generated as fluent; @@ -249,14 +244,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match (self.ptr_try_get_alloc_id(a), self.ptr_try_get_alloc_id(b)) { (Err(a), Err(b)) => { // Neither pointer points to an allocation. - // If these are inequal or null, this *will* fail the deref check below. + // This is okay only if they are the same. + if a != b { + // We'd catch this below in the "dereferenceable" check, but + // show a nicer error for this particular case. + throw_ub_custom!( + fluent::const_eval_offset_from_different_integers, + name = intrinsic_name, + ); + } (a, b) } (Err(_), _) | (_, Err(_)) => { // We managed to find a valid allocation for one pointer, but not the other. // That means they are definitely not pointing to the same allocation. throw_ub_custom!( - fluent::const_eval_different_allocations, + fluent::const_eval_offset_from_different_allocations, name = intrinsic_name, ); } @@ -264,7 +267,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Found allocation for both. They must be into the same allocation. if a_alloc_id != b_alloc_id { throw_ub_custom!( - fluent::const_eval_different_allocations, + fluent::const_eval_offset_from_different_allocations, name = intrinsic_name, ); } @@ -286,7 +289,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // a < b if intrinsic_name == sym::ptr_offset_from_unsigned { throw_ub_custom!( - fluent::const_eval_unsigned_offset_from_overflow, + fluent::const_eval_offset_from_unsigned_overflow, a_offset = a_offset, b_offset = b_offset, ); @@ -602,7 +605,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { nonoverlapping: bool, ) -> InterpResult<'tcx> { let count = self.read_target_usize(count)?; - let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?; + let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap())?; let (size, align) = (layout.size, layout.align.abi); // `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max), // but no actual allocation can be big enough for the difference to be noticeable. @@ -646,7 +649,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { byte: &OpTy<'tcx, >::Provenance>, count: &OpTy<'tcx, >::Provenance>, ) -> InterpResult<'tcx> { - let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?; + let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap())?; let dst = self.read_pointer(dst)?; let byte = self.read_scalar(byte)?.to_u8()?; @@ -685,7 +688,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { lhs: &OpTy<'tcx, >::Provenance>, rhs: &OpTy<'tcx, >::Provenance>, ) -> InterpResult<'tcx, Scalar> { - let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap().ty)?; + let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap())?; assert!(layout.is_sized()); let get_bytes = |this: &InterpCx<'mir, 'tcx, M>, diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 9af755e40de87..2d5dbbd58b3b0 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -357,7 +357,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Offset => { let ptr = left.to_scalar().to_pointer(self)?; let offset_count = right.to_scalar().to_target_isize(self)?; - let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; + let pointee_ty = left.layout.ty.builtin_deref(true).unwrap(); // We cannot overflow i64 as a type's size must be <= isize::MAX. let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index e5241f1ba19e1..809aca18990f8 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -415,7 +415,7 @@ where val: &ImmTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { let pointee_type = - val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty; + val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type"); let layout = self.layout_of(pointee_type)?; let (ptr, meta) = val.to_scalar_and_meta(); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index f9786acfc6c26..46cc9f69373f5 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt}; use rustc_middle::ty::{Instance, InstanceDef, TypeVisitableExt}; use rustc_mir_dataflow::Analysis; -use rustc_span::{sym, Span, Symbol}; +use rustc_span::{sym, Span, Symbol, DUMMY_SP}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt}; use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor}; @@ -738,7 +738,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { let cause = ObligationCause::new( terminator.source_info.span, self.body.source.def_id().expect_local(), - ObligationCauseCode::ItemObligation(callee), + ObligationCauseCode::WhereClause(callee, DUMMY_SP), ); let normalized_predicates = ocx.normalize(&cause, param_env, predicates); ocx.register_obligations(traits::predicates_for_generics( diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index dda8f3ed87d28..247a2889dc588 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -8,7 +8,7 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{ImplSource, Obligation, ObligationCause}; use rustc_middle::mir::{self, CallSource}; -use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::print::{with_no_trimmed_paths, PrintTraitRefExt as _}; use rustc_middle::ty::{ self, suggest_constraining_type_param, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef, Param, TraitRef, Ty, diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 837c02a5b769b..c95166d84e933 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -1291,7 +1291,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { )) => { let src_ty = src.ty(&self.body.local_decls, self.tcx); let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) { - src_deref.ty + src_deref } else { self.fail( location, @@ -1301,7 +1301,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { }; let dst_ty = dst.ty(&self.body.local_decls, self.tcx); let op_dst_ty = if let Some(dst_deref) = dst_ty.builtin_deref(true) { - dst_deref.ty + dst_deref } else { self.fail( location, diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 8c4af5e513217..36597507f4747 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -115,7 +115,7 @@ fn might_permit_raw_init_lax<'tcx>( // Special magic check for references and boxes (i.e., special pointer types). if let Some(pointee) = this.ty.builtin_deref(false) { - let pointee = cx.layout_of(pointee.ty)?; + let pointee = cx.layout_of(pointee)?; // We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied. if pointee.align.abi.bytes() > 1 { // 0x01-filling is not aligned. diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 80b6e72e49ba1..2b61e17efa28d 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -9,7 +9,7 @@ arrayvec = { version = "0.7", default-features = false } bitflags = "2.4.1" either = "1.0" elsa = "=1.7.1" -ena = "0.14.2" +ena = "0.14.3" indexmap = { version = "2.0.0" } jobserver_crate = { version = "0.1.28", package = "jobserver" } libc = "0.2" diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs index 9995c08345c2a..1bee159489dc7 100644 --- a/compiler/rustc_data_structures/src/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -1,3 +1,4 @@ +use crate::stable_hasher::impl_stable_traits_for_trivial_type; use crate::stable_hasher::{Hash64, StableHasher, StableHasherResult}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::hash::{Hash, Hasher}; diff --git a/compiler/rustc_data_structures/src/flock/windows.rs b/compiler/rustc_data_structures/src/flock/windows.rs index 9be1065135acd..7dc72661939be 100644 --- a/compiler/rustc_data_structures/src/flock/windows.rs +++ b/compiler/rustc_data_structures/src/flock/windows.rs @@ -2,6 +2,7 @@ use std::fs::{File, OpenOptions}; use std::io; use std::os::windows::prelude::*; use std::path::Path; +use tracing::debug; use windows::{ Win32::Foundation::{ERROR_INVALID_FUNCTION, HANDLE}, diff --git a/compiler/rustc_data_structures/src/graph/implementation/mod.rs b/compiler/rustc_data_structures/src/graph/implementation/mod.rs index 3910c6fa46d81..8cf4b4153db2f 100644 --- a/compiler/rustc_data_structures/src/graph/implementation/mod.rs +++ b/compiler/rustc_data_structures/src/graph/implementation/mod.rs @@ -22,6 +22,7 @@ use rustc_index::bit_set::BitSet; use std::fmt::Debug; +use tracing::debug; #[cfg(test)] mod tests; diff --git a/compiler/rustc_data_structures/src/graph/implementation/tests.rs b/compiler/rustc_data_structures/src/graph/implementation/tests.rs index 3ae5f5868f080..b4dbd65db940b 100644 --- a/compiler/rustc_data_structures/src/graph/implementation/tests.rs +++ b/compiler/rustc_data_structures/src/graph/implementation/tests.rs @@ -1,4 +1,5 @@ use crate::graph::implementation::*; +use tracing::debug; type TestGraph = Graph<&'static str, &'static str>; diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index 5021e5e8fc090..914a6a16348c5 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -10,6 +10,7 @@ use crate::graph::vec_graph::VecGraph; use crate::graph::{DirectedGraph, NumEdges, Successors}; use rustc_index::{Idx, IndexSlice, IndexVec}; use std::ops::Range; +use tracing::{debug, instrument}; #[cfg(test)] mod tests; diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 8dd85b25e0e21..85b5a3cdb7c37 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -42,66 +42,59 @@ #![feature(unwrap_infallible)] // tidy-alphabetical-end -#[macro_use] -extern crate tracing; - -use std::fmt; - +pub use atomic_ref::AtomicRef; +pub use ena::snapshot_vec; +pub use ena::undo_log; +pub use ena::unify; pub use rustc_index::static_assert_size; -/// This calls the passed function while ensuring it won't be inlined into the caller. -#[inline(never)] -#[cold] -pub fn outline R, R>(f: F) -> R { - f() -} +use std::fmt; +pub mod aligned; pub mod base_n; pub mod binary_search_util; pub mod captures; +pub mod fingerprint; pub mod flat_map_in_place; pub mod flock; +pub mod frozen; pub mod fx; pub mod graph; pub mod intern; pub mod jobserver; -pub mod macros; +pub mod marker; +pub mod memmap; pub mod obligation_forest; +pub mod owned_slice; +pub mod packed; +pub mod profiling; +pub mod sharded; pub mod sip128; pub mod small_c_str; pub mod snapshot_map; -pub mod svh; -pub use ena::snapshot_vec; -pub mod memmap; pub mod sorted_map; -#[macro_use] +pub mod sso; pub mod stable_hasher; -mod atomic_ref; -pub mod fingerprint; -pub mod marker; -pub mod profiling; -pub mod sharded; pub mod stack; -pub mod sync; -pub mod tiny_list; -pub mod transitive_relation; -pub mod vec_linked_list; -pub mod work_queue; -pub use atomic_ref::AtomicRef; -pub mod aligned; -pub mod frozen; -mod hashes; -pub mod owned_slice; -pub mod packed; -pub mod sso; pub mod steal; +pub mod svh; +pub mod sync; pub mod tagged_ptr; pub mod temp_dir; +pub mod transitive_relation; pub mod unhash; pub mod unord; +pub mod work_queue; -pub use ena::undo_log; -pub use ena::unify; +mod atomic_ref; +mod hashes; + +/// This calls the passed function while ensuring it won't be inlined into the caller. +#[inline(never)] +#[cold] +pub fn outline R, R>(f: F) -> R { + f() +} /// Returns a structure that calls `f` when dropped. pub fn defer(f: F) -> OnDrop { diff --git a/compiler/rustc_data_structures/src/macros.rs b/compiler/rustc_data_structures/src/macros.rs deleted file mode 100644 index e05491f6ff6e4..0000000000000 --- a/compiler/rustc_data_structures/src/macros.rs +++ /dev/null @@ -1,37 +0,0 @@ -#[macro_export] -macro_rules! enum_from_u32 { - ($(#[$attr:meta])* pub enum $name:ident { - $($(#[$var_attr:meta])* $variant:ident = $e:expr,)* - }) => { - $(#[$attr])* - pub enum $name { - $($(#[$var_attr])* $variant = $e),* - } - - impl $name { - pub fn from_u32(u: u32) -> Option<$name> { - $(if u == $name::$variant as u32 { - return Some($name::$variant) - })* - None - } - } - }; - ($(#[$attr:meta])* pub enum $name:ident { - $($(#[$var_attr:meta])* $variant:ident,)* - }) => { - $(#[$attr])* - pub enum $name { - $($(#[$var_attr])* $variant,)* - } - - impl $name { - pub fn from_u32(u: u32) -> Option<$name> { - $(if u == $name::$variant as u32 { - return Some($name::$variant) - })* - None - } - } - } -} diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index a47908648ba16..d477b86da74e8 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -70,12 +70,12 @@ //! aren't needed anymore. use crate::fx::{FxHashMap, FxHashSet}; - use std::cell::Cell; use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash; use std::marker::PhantomData; +use tracing::debug; mod graphviz; diff --git a/compiler/rustc_data_structures/src/packed.rs b/compiler/rustc_data_structures/src/packed.rs index b8d4b295dfa10..0a392d91988f0 100644 --- a/compiler/rustc_data_structures/src/packed.rs +++ b/compiler/rustc_data_structures/src/packed.rs @@ -3,8 +3,10 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use std::cmp::Ordering; use std::fmt; -#[repr(packed(8))] +/// A packed 128-bit integer. Useful for reducing the size of structures in +/// some cases. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[repr(packed(8))] pub struct Pu128(pub u128); impl Pu128 { diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 2569684df3fc0..c6d51a5d6b4f7 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -99,6 +99,7 @@ pub use measureme::EventId; use measureme::{EventIdBuilder, Profiler, SerializableString, StringId}; use parking_lot::RwLock; use smallvec::SmallVec; +use tracing::warn; bitflags::bitflags! { #[derive(Clone, Copy)] diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index 8418b4bbd4702..b5bdf2e179042 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -296,6 +296,8 @@ macro_rules! impl_stable_traits_for_trivial_type { }; } +pub(crate) use impl_stable_traits_for_trivial_type; + impl_stable_traits_for_trivial_type!(i8); impl_stable_traits_for_trivial_type!(i16); impl_stable_traits_for_trivial_type!(i32); diff --git a/compiler/rustc_data_structures/src/tiny_list.rs b/compiler/rustc_data_structures/src/tiny_list.rs deleted file mode 100644 index 11a408f216a14..0000000000000 --- a/compiler/rustc_data_structures/src/tiny_list.rs +++ /dev/null @@ -1,80 +0,0 @@ -//! A singly-linked list. -//! -//! Using this data structure only makes sense under very specific -//! circumstances: -//! -//! - If you have a list that rarely stores more than one element, then this -//! data-structure can store the element without allocating and only uses as -//! much space as an `Option<(T, usize)>`. If T can double as the `Option` -//! discriminant, it will even only be as large as `T, usize`. -//! -//! If you expect to store more than 1 element in the common case, steer clear -//! and use a `Vec`, `Box<[T]>`, or a `SmallVec`. - -#[cfg(test)] -mod tests; - -#[derive(Clone)] -pub struct TinyList { - head: Option>, -} - -impl TinyList { - #[inline] - pub fn new() -> TinyList { - TinyList { head: None } - } - - #[inline] - pub fn new_single(data: T) -> TinyList { - TinyList { head: Some(Element { data, next: None }) } - } - - #[inline] - pub fn insert(&mut self, data: T) { - self.head = Some(Element { data, next: self.head.take().map(Box::new) }); - } - - #[inline] - pub fn remove(&mut self, data: &T) -> bool { - self.head = match &mut self.head { - Some(head) if head.data == *data => head.next.take().map(|x| *x), - Some(head) => return head.remove_next(data), - None => return false, - }; - true - } - - #[inline] - pub fn contains(&self, data: &T) -> bool { - let mut elem = self.head.as_ref(); - while let Some(e) = elem { - if &e.data == data { - return true; - } - elem = e.next.as_deref(); - } - false - } -} - -#[derive(Clone)] -struct Element { - data: T, - next: Option>>, -} - -impl Element { - fn remove_next(mut self: &mut Self, data: &T) -> bool { - loop { - match self.next { - Some(ref mut next) if next.data == *data => { - self.next = next.next.take(); - return true; - } - Some(ref mut next) => self = next, - None => return false, - } - } - } -} diff --git a/compiler/rustc_data_structures/src/tiny_list/tests.rs b/compiler/rustc_data_structures/src/tiny_list/tests.rs deleted file mode 100644 index 4b95e62bef02b..0000000000000 --- a/compiler/rustc_data_structures/src/tiny_list/tests.rs +++ /dev/null @@ -1,155 +0,0 @@ -use super::*; - -extern crate test; -use test::{black_box, Bencher}; - -impl TinyList { - fn len(&self) -> usize { - let (mut elem, mut count) = (self.head.as_ref(), 0); - while let Some(e) = elem { - count += 1; - elem = e.next.as_deref(); - } - count - } -} - -#[test] -fn test_contains_and_insert() { - fn do_insert(i: u32) -> bool { - i % 2 == 0 - } - - let mut list = TinyList::new(); - - for i in 0..10 { - for j in 0..i { - if do_insert(j) { - assert!(list.contains(&j)); - } else { - assert!(!list.contains(&j)); - } - } - - assert!(!list.contains(&i)); - - if do_insert(i) { - list.insert(i); - assert!(list.contains(&i)); - } - } -} - -#[test] -fn test_remove_first() { - let mut list = TinyList::new(); - list.insert(1); - list.insert(2); - list.insert(3); - list.insert(4); - assert_eq!(list.len(), 4); - - assert!(list.remove(&4)); - assert!(!list.contains(&4)); - - assert_eq!(list.len(), 3); - assert!(list.contains(&1)); - assert!(list.contains(&2)); - assert!(list.contains(&3)); -} - -#[test] -fn test_remove_last() { - let mut list = TinyList::new(); - list.insert(1); - list.insert(2); - list.insert(3); - list.insert(4); - assert_eq!(list.len(), 4); - - assert!(list.remove(&1)); - assert!(!list.contains(&1)); - - assert_eq!(list.len(), 3); - assert!(list.contains(&2)); - assert!(list.contains(&3)); - assert!(list.contains(&4)); -} - -#[test] -fn test_remove_middle() { - let mut list = TinyList::new(); - list.insert(1); - list.insert(2); - list.insert(3); - list.insert(4); - assert_eq!(list.len(), 4); - - assert!(list.remove(&2)); - assert!(!list.contains(&2)); - - assert_eq!(list.len(), 3); - assert!(list.contains(&1)); - assert!(list.contains(&3)); - assert!(list.contains(&4)); -} - -#[test] -fn test_remove_single() { - let mut list = TinyList::new(); - list.insert(1); - assert_eq!(list.len(), 1); - - assert!(list.remove(&1)); - assert!(!list.contains(&1)); - - assert_eq!(list.len(), 0); -} - -#[bench] -fn bench_insert_empty(b: &mut Bencher) { - b.iter(|| { - let mut list = black_box(TinyList::new()); - list.insert(1); - list - }) -} - -#[bench] -fn bench_insert_one(b: &mut Bencher) { - b.iter(|| { - let mut list = black_box(TinyList::new_single(0)); - list.insert(1); - list - }) -} - -#[bench] -fn bench_contains_empty(b: &mut Bencher) { - b.iter(|| black_box(TinyList::new()).contains(&1)); -} - -#[bench] -fn bench_contains_unknown(b: &mut Bencher) { - b.iter(|| black_box(TinyList::new_single(0)).contains(&1)); -} - -#[bench] -fn bench_contains_one(b: &mut Bencher) { - b.iter(|| black_box(TinyList::new_single(1)).contains(&1)); -} - -#[bench] -fn bench_remove_empty(b: &mut Bencher) { - b.iter(|| black_box(TinyList::new()).remove(&1)); -} - -#[bench] -fn bench_remove_unknown(b: &mut Bencher) { - b.iter(|| black_box(TinyList::new_single(0)).remove(&1)); -} - -#[bench] -fn bench_remove_one(b: &mut Bencher) { - b.iter(|| black_box(TinyList::new_single(1)).remove(&1)); -} diff --git a/compiler/rustc_data_structures/src/vec_linked_list.rs b/compiler/rustc_data_structures/src/vec_linked_list.rs deleted file mode 100644 index fda72c9a3b204..0000000000000 --- a/compiler/rustc_data_structures/src/vec_linked_list.rs +++ /dev/null @@ -1,70 +0,0 @@ -use rustc_index::{Idx, IndexVec}; - -pub fn iter( - first: Option, - links: &Ls, -) -> impl Iterator + '_ -where - Ls: Links, -{ - VecLinkedListIterator { links, current: first } -} - -pub struct VecLinkedListIterator -where - Ls: Links, -{ - links: Ls, - current: Option, -} - -impl Iterator for VecLinkedListIterator -where - Ls: Links, -{ - type Item = Ls::LinkIndex; - - fn next(&mut self) -> Option { - if let Some(c) = self.current { - self.current = ::next(&self.links, c); - Some(c) - } else { - None - } - } -} - -pub trait Links { - type LinkIndex: Copy; - - fn next(links: &Self, index: Self::LinkIndex) -> Option; -} - -impl Links for &Ls -where - Ls: Links, -{ - type LinkIndex = Ls::LinkIndex; - - fn next(links: &Self, index: Ls::LinkIndex) -> Option { - ::next(links, index) - } -} - -pub trait LinkElem { - type LinkIndex: Copy; - - fn next(elem: &Self) -> Option; -} - -impl Links for IndexVec -where - E: LinkElem, - L: Idx, -{ - type LinkIndex = L; - - fn next(links: &Self, index: L) -> Option { - ::next(&links[index]) - } -} diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 4696917554ffb..2cc0167dbaa6e 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -94,6 +94,18 @@ into_diag_arg_using_display!( ErrCode, ); +impl IntoDiagArg for rustc_type_ir::TraitRef { + fn into_diag_arg(self) -> DiagArgValue { + self.to_string().into_diag_arg() + } +} + +impl IntoDiagArg for rustc_type_ir::ExistentialTraitRef { + fn into_diag_arg(self) -> DiagArgValue { + self.to_string().into_diag_arg() + } +} + into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize); impl IntoDiagArg for bool { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index f61cebc02562a..ddf7b1a007a8e 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1194,8 +1194,8 @@ impl InvocationCollectorNode for P { match &ut.kind { ast::UseTreeKind::Glob => {} ast::UseTreeKind::Simple(_) => idents.push(ut.ident()), - ast::UseTreeKind::Nested(nested) => { - for (ut, _) in nested { + ast::UseTreeKind::Nested { items, .. } => { + for (ut, _) in items { collect_use_tree_leaves(ut, idents); } } diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 7026425e167c8..e21f041d69afd 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -174,7 +174,10 @@ pub(crate) fn placeholder( }]), AstFragmentKind::Variants => AstFragment::Variants(smallvec![ast::Variant { attrs: Default::default(), - data: ast::VariantData::Struct { fields: Default::default(), recovered: false }, + data: ast::VariantData::Struct { + fields: Default::default(), + recovered: ast::Recovered::No + }, disr_expr: None, id, ident, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 244c479120dc2..7d991e21ff3d2 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1308,9 +1308,9 @@ pub struct LetExpr<'hir> { pub pat: &'hir Pat<'hir>, pub ty: Option<&'hir Ty<'hir>>, pub init: &'hir Expr<'hir>, - /// `Some` when this let expressions is not in a syntanctically valid location. + /// `Recovered::Yes` when this let expressions is not in a syntanctically valid location. /// Used to prevent building MIR in such situations. - pub is_recovered: Option, + pub recovered: ast::Recovered, } #[derive(Debug, Clone, Copy, HashStable_Generic)] @@ -3030,11 +3030,7 @@ pub enum VariantData<'hir> { /// A struct variant. /// /// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`. - Struct { - fields: &'hir [FieldDef<'hir>], - // FIXME: investigate making this a `Option` - recovered: bool, - }, + Struct { fields: &'hir [FieldDef<'hir>], recovered: ast::Recovered }, /// A tuple variant. /// /// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index fa89a4a44ef5a..0b095db953b08 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -768,7 +768,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) ExprKind::DropTemps(ref subexpression) => { try_visit!(visitor.visit_expr(subexpression)); } - ExprKind::Let(LetExpr { span: _, pat, ty, init, is_recovered: _ }) => { + ExprKind::Let(LetExpr { span: _, pat, ty, init, recovered: _ }) => { // match the visit order in walk_local try_visit!(visitor.visit_expr(init)); try_visit!(visitor.visit_pat(pat)); diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index e870a04127ada..c4be67cdd887f 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -55,21 +55,27 @@ macro_rules! language_item_table { ( $( $(#[$attr:meta])* $variant:ident, $module:ident :: $name:ident, $method:ident, $target:expr, $generics:expr; )* ) => { - - rustc_data_structures::enum_from_u32! { - /// A representation of all the valid lang items in Rust. - #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)] - pub enum LangItem { - $( - #[doc = concat!("The `", stringify!($name), "` lang item.")] - /// - $(#[$attr])* - $variant, - )* - } + /// A representation of all the valid lang items in Rust. + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)] + pub enum LangItem { + $( + #[doc = concat!("The `", stringify!($name), "` lang item.")] + $(#[$attr])* + $variant, + )* } impl LangItem { + fn from_u32(u: u32) -> Option { + // This implementation is clumsy, but makes no assumptions + // about how discriminant tags are allocated within the + // range `0 .. std::mem::variant_count::()`. + $(if u == LangItem::$variant as u32 { + return Some(LangItem::$variant) + })* + None + } + /// Returns the `name` symbol in `#[lang = "$name"]`. /// For example, [`LangItem::PartialEq`]`.name()` /// would result in [`sym::eq`] since it is `#[lang = "eq"]`. @@ -147,7 +153,7 @@ language_item_table! { Clone, sym::clone, clone_trait, Target::Trait, GenericRequirement::None; Sync, sym::sync, sync_trait, Target::Trait, GenericRequirement::Exact(0); DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, Target::Trait, GenericRequirement::None; - /// The associated item of the [`DiscriminantKind`] trait. + /// The associated item of the `DiscriminantKind` trait. Discriminant, sym::discriminant_type, discriminant_type, Target::AssocTy, GenericRequirement::None; PointeeTrait, sym::pointee_trait, pointee_trait, Target::Trait, GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index f101c595bdf35..2bf14a2461f31 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -68,28 +68,27 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { } // Otherwise, deref if type is derefable: - let (kind, new_ty) = if let Some(ty::TypeAndMut { ty, .. }) = - self.state.cur_ty.builtin_deref(self.include_raw_pointers) - { - debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty)); - // NOTE: we may still need to normalize the built-in deref in case - // we have some type like `&::Assoc`, since users of - // autoderef expect this type to have been structurally normalized. - if self.infcx.next_trait_solver() - && let ty::Alias(..) = ty.kind() - { - let (normalized_ty, obligations) = self.structurally_normalize(ty)?; - self.state.obligations.extend(obligations); - (AutoderefKind::Builtin, normalized_ty) + let (kind, new_ty) = + if let Some(ty) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) { + debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty)); + // NOTE: we may still need to normalize the built-in deref in case + // we have some type like `&::Assoc`, since users of + // autoderef expect this type to have been structurally normalized. + if self.infcx.next_trait_solver() + && let ty::Alias(..) = ty.kind() + { + let (normalized_ty, obligations) = self.structurally_normalize(ty)?; + self.state.obligations.extend(obligations); + (AutoderefKind::Builtin, normalized_ty) + } else { + (AutoderefKind::Builtin, ty) + } + } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { + // The overloaded deref check already normalizes the pointee type. + (AutoderefKind::Overloaded, ty) } else { - (AutoderefKind::Builtin, ty) - } - } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { - // The overloaded deref check already normalizes the pointee type. - (AutoderefKind::Overloaded, ty) - } else { - return None; - }; + return None; + }; self.state.steps.push((self.state.cur_ty, kind)); debug!( diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 32e1b19eaaeb9..fb9d97ba08b01 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -561,7 +561,7 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe let generics = tcx.generics_of(generics); def_id = generics.parent; - for param in &generics.params { + for param in &generics.own_params { if expected_captures.contains(¶m.def_id) { assert_eq!( variances[param.index as usize], @@ -778,7 +778,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { let def_id = item.id.owner_id.def_id; let generics = tcx.generics_of(def_id); let own_counts = generics.own_counts(); - if generics.params.len() - own_counts.lifetimes != 0 { + if generics.own_params.len() - own_counts.lifetimes != 0 { let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) { (_, 0) => ("type", "types", Some("u32")), @@ -1544,7 +1544,7 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD .collect::>() }); - let mut params_used = BitSet::new_empty(generics.params.len()); + let mut params_used = BitSet::new_empty(generics.own_params.len()); for leaf in ty.walk() { if let GenericArgKind::Type(leaf_ty) = leaf.unpack() && let ty::Param(param) = leaf_ty.kind() @@ -1554,7 +1554,7 @@ fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalD } } - for param in &generics.params { + for param in &generics.own_params { if !params_used.contains(param.index) && let ty::GenericParamDefKind::Type { .. } = param.kind { 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 d2759087cb471..db223f9d80f39 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -9,7 +9,6 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; use rustc_hir::{GenericParamKind, ImplItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{util, FulfillmentError}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; @@ -176,7 +175,7 @@ fn compare_method_predicate_entailment<'tcx>( let cause = ObligationCause::new( impl_m_span, impl_m_def_id, - ObligationCauseCode::CompareImplItemObligation { + ObligationCauseCode::CompareImplItem { impl_item_def_id: impl_m_def_id, trait_item_def_id: trait_m.def_id, kind: impl_m.kind, @@ -237,7 +236,7 @@ fn compare_method_predicate_entailment<'tcx>( let cause = ObligationCause::new( span, impl_m_def_id, - ObligationCauseCode::CompareImplItemObligation { + ObligationCauseCode::CompareImplItem { impl_item_def_id: impl_m_def_id, trait_item_def_id: trait_m.def_id, kind: impl_m.kind, @@ -465,7 +464,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let cause = ObligationCause::new( return_span, impl_m_def_id, - ObligationCauseCode::CompareImplItemObligation { + ObligationCauseCode::CompareImplItem { impl_item_def_id: impl_m_def_id, trait_item_def_id: trait_m.def_id, kind: impl_m.kind, @@ -716,7 +715,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( // since we previously enforce that the trait method and impl method have the // same generics. let num_trait_args = trait_to_impl_args.len(); - let num_impl_args = tcx.generics_of(impl_m.container_id(tcx)).params.len(); + let num_impl_args = tcx.generics_of(impl_m.container_id(tcx)).own_params.len(); let ty = match ty.try_fold_with(&mut RemapHiddenTyRegions { tcx, map, @@ -800,10 +799,7 @@ impl<'tcx> TypeFolder> for ImplTraitInTraitCollector<'_, 'tcx> { bug!("FIXME(RPITIT): error here"); } // Replace with infer var - let infer_ty = self - .ocx - .infcx - .next_ty_var(TypeVariableOrigin { span: self.span, param_def_id: None }); + let infer_ty = self.ocx.infcx.next_ty_var(self.span); self.types.insert(proj.def_id, (infer_ty, proj.args)); // Recurse into bounds for (pred, pred_span) in self @@ -823,7 +819,7 @@ impl<'tcx> TypeFolder> for ImplTraitInTraitCollector<'_, 'tcx> { ObligationCause::new( self.span, self.body_id, - ObligationCauseCode::BindingObligation(proj.def_id, pred_span), + ObligationCauseCode::WhereClause(proj.def_id, pred_span), ), self.param_env, pred, @@ -1494,14 +1490,16 @@ fn compare_synthetic_generics<'tcx>( let mut error_found = None; let impl_m_generics = tcx.generics_of(impl_m.def_id); let trait_m_generics = tcx.generics_of(trait_m.def_id); - let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| match param.kind { - GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)), - GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None, - }); - let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| match param.kind { - GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)), - GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None, - }); + let impl_m_type_params = + impl_m_generics.own_params.iter().filter_map(|param| match param.kind { + GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)), + GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None, + }); + let trait_m_type_params = + trait_m_generics.own_params.iter().filter_map(|param| match param.kind { + GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)), + GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None, + }); for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic)) in iter::zip(impl_m_type_params, trait_m_type_params) { @@ -1639,7 +1637,7 @@ fn compare_generic_param_kinds<'tcx>( assert_eq!(impl_item.kind, trait_item.kind); let ty_const_params_of = |def_id| { - tcx.generics_of(def_id).params.iter().filter(|param| { + tcx.generics_of(def_id).own_params.iter().filter(|param| { matches!( param.kind, GenericParamDefKind::Const { .. } | GenericParamDefKind::Type { .. } @@ -1754,7 +1752,7 @@ fn compare_const_predicate_entailment<'tcx>( let impl_ty = tcx.type_of(impl_ct_def_id).instantiate_identity(); let trait_ty = tcx.type_of(trait_ct.def_id).instantiate(tcx, trait_to_impl_args); - let code = ObligationCauseCode::CompareImplItemObligation { + let code = ObligationCauseCode::CompareImplItem { impl_item_def_id: impl_ct_def_id, trait_item_def_id: trait_ct.def_id, kind: impl_ct.kind, @@ -1926,7 +1924,7 @@ fn compare_type_predicate_entailment<'tcx>( let cause = ObligationCause::new( span, impl_ty_def_id, - ObligationCauseCode::CompareImplItemObligation { + ObligationCauseCode::CompareImplItem { impl_item_def_id: impl_ty.def_id.expect_local(), trait_item_def_id: trait_ty.def_id, kind: impl_ty.kind, @@ -2013,11 +2011,7 @@ pub(super) fn check_type_bounds<'tcx>( }, ); let mk_cause = |span: Span| { - let code = if span.is_dummy() { - traits::ItemObligation(trait_ty.def_id) - } else { - traits::BindingObligation(trait_ty.def_id, span) - }; + let code = ObligationCauseCode::WhereClause(trait_ty.def_id, span); ObligationCause::new(impl_ty_span, impl_ty_def_id, code) }; @@ -2140,7 +2134,7 @@ fn param_env_with_gat_bounds<'tcx>( }; let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> = - smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len()); + smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).own_params.len()); // Extend the impl's identity args with late-bound GAT vars let normalize_impl_ty_args = ty::GenericArgs::identity_for_item(tcx, container_id) .extend_to(tcx, impl_ty.def_id, |param, _| match param.kind { @@ -2253,7 +2247,7 @@ fn try_report_async_mismatch<'tcx>( }; for error in errors { - if let traits::BindingObligation(def_id, _) = *error.root_obligation.cause.code() + if let ObligationCauseCode::WhereClause(def_id, _) = *error.root_obligation.cause.code() && def_id == async_future_def_id && let Some(proj) = error.root_obligation.predicate.to_opt_poly_projection_pred() && let Some(proj) = proj.no_bound_vars() diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 82a6b6b6f2cb5..be412dde96803 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -5,6 +5,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; +use rustc_infer::traits::ObligationCauseCode; use rustc_middle::ty::util::CheckRegions; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, TyCtxt}; @@ -139,7 +140,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( for (pred, span) in tcx.predicates_of(drop_impl_def_id).instantiate_identity(tcx) { let normalize_cause = traits::ObligationCause::misc(span, adt_def_id); let pred = ocx.normalize(&normalize_cause, param_env, pred); - let cause = traits::ObligationCause::new(span, adt_def_id, traits::DropImpl); + let cause = traits::ObligationCause::new(span, adt_def_id, ObligationCauseCode::DropImpl); ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, pred)); } diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 5b127e0bf496a..e50af9605fd0d 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -431,7 +431,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { } let gat_generics = tcx.generics_of(gat_def_id); // FIXME(jackh726): we can also warn in the more general case - if gat_generics.params.is_empty() { + if gat_generics.own_params.is_empty() { continue; } @@ -1136,7 +1136,7 @@ fn check_type_defn<'tcx>( traits::ObligationCause::new( hir_ty.span, wfcx.body_def_id, - traits::FieldSized { + ObligationCauseCode::FieldSized { adt_kind: match &item.kind { ItemKind::Struct(..) => AdtKind::Struct, ItemKind::Union(..) => AdtKind::Union, @@ -1161,7 +1161,7 @@ fn check_type_defn<'tcx>( let cause = traits::ObligationCause::new( tcx.def_span(discr_def_id), wfcx.body_def_id, - traits::MiscObligation, + ObligationCauseCode::Misc, ); wfcx.register_obligation(traits::Obligation::new( tcx, @@ -1278,7 +1278,11 @@ fn check_item_type( wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(item_id)), item_ty.into()); if forbid_unsized { wfcx.register_bound( - traits::ObligationCause::new(ty_span, wfcx.body_def_id, traits::WellFormed(None)), + traits::ObligationCause::new( + ty_span, + wfcx.body_def_id, + ObligationCauseCode::WellFormed(None), + ), wfcx.param_env, item_ty, tcx.require_lang_item(LangItem::Sized, None), @@ -1293,7 +1297,11 @@ fn check_item_type( if should_check_for_sync { wfcx.register_bound( - traits::ObligationCause::new(ty_span, wfcx.body_def_id, traits::SharedStatic), + traits::ObligationCause::new( + ty_span, + wfcx.body_def_id, + ObligationCauseCode::SharedStatic, + ), wfcx.param_env, item_ty, tcx.require_lang_item(LangItem::Sync, Some(ty_span)), @@ -1400,7 +1408,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id // struct Foo> { .. } // // Here, the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold. - for param in &generics.params { + for param in &generics.own_params { match param.kind { GenericParamDefKind::Type { .. } => { if is_our_default(param) { @@ -1542,7 +1550,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id let cause = traits::ObligationCause::new( sp, wfcx.body_def_id, - traits::ItemObligation(def_id.to_def_id()), + ObligationCauseCode::WhereClause(def_id.to_def_id(), DUMMY_SP), ); traits::Obligation::new(tcx, cause, wfcx.param_env, pred) }); @@ -1879,7 +1887,7 @@ fn check_variances_for_type_defn<'tcx>( continue; } - let ty_param = &ty_generics.params[index]; + let ty_param = &ty_generics.own_params[index]; let hir_param = &hir_generics.params[index]; if ty_param.def_id != hir_param.def_id.into() { @@ -1982,7 +1990,11 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { let obligation = traits::Obligation::new( tcx, - traits::ObligationCause::new(span, self.body_def_id, traits::TrivialBound), + traits::ObligationCause::new( + span, + self.body_def_id, + ObligationCauseCode::TrivialBound, + ), empty_env, pred, ); diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 0b6c60e4ba296..8f0aba1c38c1d 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -14,6 +14,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::{self, RegionResolutionError}; use rustc_infer::traits::Obligation; use rustc_middle::ty::adjustment::CoerceUnsizedInfo; +use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 819e0925f68df..8e1b2e8e65c52 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -571,7 +571,7 @@ impl<'cx, 'tcx> TypeFolder> for TyVarReplacer<'cx, 'tcx> { if let Some(def_id) = origin.param_def_id { // The generics of an `impl` don't have a parent, we can index directly. let index = self.generics.param_def_id_to_index[&def_id]; - let name = self.generics.params[index as usize].name; + let name = self.generics.own_params[index as usize].name; Ty::new_param(self.infcx.tcx, index, name) } else { diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index 13ce4f0759377..287354292102c 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -3,6 +3,7 @@ use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir::Unsafety; +use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{ImplPolarity::*, ImplTraitHeader, TraitDef, TyCtxt}; use rustc_span::def_id::LocalDefId; use rustc_span::ErrorGuaranteed; @@ -14,7 +15,7 @@ pub(super) fn check_item( trait_def: &TraitDef, ) -> Result<(), ErrorGuaranteed> { let unsafe_attr = - tcx.generics_of(def_id).params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle"); + tcx.generics_of(def_id).own_params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle"); let trait_ref = trait_header.trait_ref.instantiate_identity(); match (trait_def.unsafety, unsafe_attr, trait_header.unsafety, trait_header.polarity) { diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 9198ceb8f59db..566f818f89958 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -14,6 +14,7 @@ //! At present, however, we do run collection across all items in the //! crate as a kind of pass. This should eventually be factored away. +use rustc_ast::Recovered; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordMap; @@ -1005,10 +1006,7 @@ fn lower_variant( vis: tcx.visibility(f.def_id), }) .collect(); - let recovered = match def { - hir::VariantData::Struct { recovered, .. } => *recovered, - _ => false, - }; + let recovered = matches!(def, hir::VariantData::Struct { recovered: Recovered::Yes(_), .. }); ty::VariantDef::new( ident.name, variant_did.map(LocalDefId::to_def_id), diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index f83ddc51c76e2..6b41f79cf1e7f 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -22,28 +22,28 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { let trait_def_id = tcx.parent(fn_def_id); let opaque_ty_generics = tcx.generics_of(opaque_def_id); let opaque_ty_parent_count = opaque_ty_generics.parent_count; - let mut params = opaque_ty_generics.params.clone(); + let mut own_params = opaque_ty_generics.own_params.clone(); let parent_generics = tcx.generics_of(trait_def_id); - let parent_count = parent_generics.parent_count + parent_generics.params.len(); + let parent_count = parent_generics.parent_count + parent_generics.own_params.len(); - let mut trait_fn_params = tcx.generics_of(fn_def_id).params.clone(); + let mut trait_fn_params = tcx.generics_of(fn_def_id).own_params.clone(); - for param in &mut params { + for param in &mut own_params { param.index = param.index + parent_count as u32 + trait_fn_params.len() as u32 - opaque_ty_parent_count as u32; } - trait_fn_params.extend(params); - params = trait_fn_params; + trait_fn_params.extend(own_params); + own_params = trait_fn_params; let param_def_id_to_index = - params.iter().map(|param| (param.def_id, param.index)).collect(); + own_params.iter().map(|param| (param.def_id, param.index)).collect(); return ty::Generics { parent: Some(trait_def_id), parent_count, - params, + own_params, param_def_id_to_index, has_self: opaque_ty_generics.has_self, has_late_bound_regions: opaque_ty_generics.has_late_bound_regions, @@ -124,9 +124,9 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { let generics = tcx.generics_of(parent_def_id.to_def_id()); let param_def_idx = generics.param_def_id_to_index[¶m_id.to_def_id()]; // In the above example this would be .params[..N#0] - let params = generics.params_to(param_def_idx as usize, tcx).to_owned(); + let own_params = generics.params_to(param_def_idx as usize, tcx).to_owned(); let param_def_id_to_index = - params.iter().map(|param| (param.def_id, param.index)).collect(); + own_params.iter().map(|param| (param.def_id, param.index)).collect(); return ty::Generics { // we set the parent of these generics to be our parent's parent so that we @@ -134,7 +134,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // struct Foo; parent: generics.parent, parent_count: generics.parent_count, - params, + own_params, param_def_id_to_index, has_self: generics.has_self, has_late_bound_regions: generics.has_late_bound_regions, @@ -274,17 +274,17 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { parent_has_self = generics.has_self; host_effect_index = generics.host_effect_index; own_start = generics.count() as u32; - generics.parent_count + generics.params.len() + generics.parent_count + generics.own_params.len() }); - let mut params: Vec<_> = Vec::with_capacity(hir_generics.params.len() + has_self as usize); + let mut own_params: Vec<_> = Vec::with_capacity(hir_generics.params.len() + has_self as usize); if let Some(opt_self) = opt_self { - params.push(opt_self); + own_params.push(opt_self); } let early_lifetimes = super::early_bound_lifetimes_from_generics(tcx, hir_generics); - params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef { + own_params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef { name: param.name.ident().name, index: own_start + i as u32, def_id: param.def_id.to_def_id(), @@ -293,7 +293,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { })); // Now create the real type and const parameters. - let type_start = own_start - has_self as u32 + params.len() as u32; + let type_start = own_start - has_self as u32 + own_params.len() as u32; let mut i: u32 = 0; let mut next_index = || { let prev = i; @@ -304,7 +304,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \ `struct`, `enum`, `type`, or `trait` definitions"; - params.extend(hir_generics.params.iter().filter_map(|param| match param.kind { + own_params.extend(hir_generics.params.iter().filter_map(|param| match param.kind { GenericParamKind::Lifetime { .. } => None, GenericParamKind::Type { default, synthetic, .. } => { if default.is_some() { @@ -404,7 +404,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { ][..], }; - params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef { + own_params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef { index: next_index(), name: Symbol::intern(arg), def_id: def_id.to_def_id(), @@ -415,7 +415,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { // provide junk type parameter defs for const blocks. if let Node::ConstBlock(_) = node { - params.push(ty::GenericParamDef { + own_params.push(ty::GenericParamDef { index: next_index(), name: Symbol::intern(""), def_id: def_id.to_def_id(), @@ -424,12 +424,13 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { }); } - let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect(); + let param_def_id_to_index = + own_params.iter().map(|param| (param.def_id, param.index)).collect(); ty::Generics { parent: parent_def_id, parent_count, - params, + own_params, param_def_id_to_index, has_self: has_self || parent_has_self, has_late_bound_regions: has_late_bound_regions(tcx, node), diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 472657290ed1f..7e82571d172f1 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -73,8 +73,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen // opaque lifetimes, which explains the slicing below. compute_bidirectional_outlives_predicates( tcx, - &tcx.generics_of(def_id.to_def_id()).params - [tcx.generics_of(fn_def_id).params.len()..], + &tcx.generics_of(def_id.to_def_id()).own_params + [tcx.generics_of(fn_def_id).own_params.len()..], &mut predicates, ); @@ -300,7 +300,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen }; debug!(?lifetimes); - compute_bidirectional_outlives_predicates(tcx, &generics.params, &mut predicates); + compute_bidirectional_outlives_predicates(tcx, &generics.own_params, &mut predicates); debug!(?predicates); } 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 a5f038d383d88..3ef132a3e8c97 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -1562,7 +1562,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { ObjectLifetimeDefault::Ambiguous => None, }; generics - .params + .own_params .iter() .filter_map(|param| { match self.tcx.def_kind(param.def_id) { @@ -1668,7 +1668,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { binding.ident, ty::AssocKind::Fn, ) { - bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).params.iter().map( + bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).own_params.iter().map( |param| match param.kind { ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region( ty::BoundRegionKind::BrNamed(param.def_id, param.name), @@ -2003,7 +2003,8 @@ fn is_late_bound_map( // just consider args to be unconstrained. let generics = self.tcx.generics_of(alias_def); let mut walker = ConstrainedCollectorPostHirTyLowering { - arg_is_constrained: vec![false; generics.params.len()].into_boxed_slice(), + arg_is_constrained: vec![false; generics.own_params.len()] + .into_boxed_slice(), }; walker.visit_ty(self.tcx.type_of(alias_def).instantiate_identity()); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 5ccfd06f25822..24a5349858ade 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -255,7 +255,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { debug!(?parent_node); debug!(?generics, ?arg_idx); if let Some(param_def_id) = generics - .params + .own_params .iter() .filter(|param| param.kind.is_ty_or_const()) .nth(match generics.has_self && generics.parent.is_none() { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index 11bd3e5282dc1..de12475678ca3 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -5,6 +5,7 @@ use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt}; use rustc_span::symbol::Ident; use rustc_span::{ErrorGuaranteed, Span, Symbol}; 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 8e64a9425bb9f..38dfa8d57d34b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -17,6 +17,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_infer::traits::FulfillmentError; use rustc_middle::query::Key; +use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::{self, suggest_constraining_type_param}; use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt}; @@ -1299,7 +1300,7 @@ pub fn prohibit_assoc_item_binding( // same name as the assoc type name in type binding let generics = tcx.generics_of(def_id); let matching_param = - generics.params.iter().find(|p| p.name.as_str() == binding.ident.as_str()); + generics.own_params.iter().find(|p| p.name.as_str() == binding.ident.as_str()); // Now emit the appropriate suggestion if let Some(matching_param) = matching_param { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index e6a7dfa759c8e..749f78e79201e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -196,7 +196,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( let mut args: SmallVec<[ty::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count); // Iterate over each segment of the path. while let Some((def_id, defs)) = stack.pop() { - let mut params = defs.params.iter().peekable(); + let mut params = defs.own_params.iter().peekable(); // If we have already computed the generic arguments for parents, // we can use those directly. @@ -312,7 +312,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( // We're going to iterate over the parameters to sort them out, and // show that order to the user as a possible order for the parameters let mut param_types_present = defs - .params + .own_params .iter() .map(|param| (param.kind.to_ord(), param.clone())) .collect::>(); @@ -435,13 +435,13 @@ pub(crate) fn check_generic_arg_count( // Subtracting from param count to ensure type params synthesized from `impl Trait` // cannot be explicitly specified. let synth_type_param_count = gen_params - .params + .own_params .iter() .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })) .count(); let named_type_param_count = param_counts.types - has_self as usize - synth_type_param_count; let synth_const_param_count = gen_params - .params + .own_params .iter() .filter(|param| { matches!(param.kind, ty::GenericParamDefKind::Const { is_host_effect: true, .. }) 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 f7213442ac2dd..591d554d335e1 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -411,7 +411,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Traits always have `Self` as a generic parameter, which means they will not return early // here and so associated type bindings will be handled regardless of whether there are any // non-`Self` generic parameters. - if generics.params.is_empty() { + if generics.own_params.is_empty() { return (tcx.mk_args(parent_args), arg_count); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs index 97ba946b7e013..37d4d4ec35581 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs @@ -7,7 +7,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS; use rustc_middle::ty::fold::BottomUpFolder; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{DynKind, ToPredicate}; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits::error_reporting::report_object_safety_error; @@ -227,7 +227,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .skip(1) // Remove `Self` for `ExistentialPredicate`. .map(|(index, arg)| { if arg == dummy_self.into() { - let param = &generics.params[index]; + let param = &generics.own_params[index]; missing_type_params.push(param.name); Ty::new_misc_error(tcx).into() } else if arg.walk().any(|arg| arg == dummy_self.into()) { diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 7014b23ff07de..d6ba5fa9b5b04 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -163,15 +163,17 @@ fn diagnostic_hir_wf_check<'tcx>( kind: hir::GenericParamKind::Type { default: Some(ty), .. }, .. }) => vec![*ty], - hir::Node::AnonConst(_) - if let Some(const_param_id) = - tcx.hir().opt_const_param_default_param_def_id(hir_id) + hir::Node::AnonConst(_) => { + if let Some(const_param_id) = tcx.hir().opt_const_param_default_param_def_id(hir_id) && let hir::Node::GenericParam(hir::GenericParam { kind: hir::GenericParamKind::Const { ty, .. }, .. - }) = tcx.hir_node_by_def_id(const_param_id) => - { - vec![*ty] + }) = tcx.hir_node_by_def_id(const_param_id) + { + vec![*ty] + } else { + vec![] + } } ref node => bug!("Unexpected node {:?}", node), }, diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index caa85092415b9..002be61196aa8 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -114,7 +114,7 @@ fn enforce_impl_params_are_constrained( .collect(); let mut res = Ok(()); - for param in &impl_generics.params { + for param in &impl_generics.own_params { match param.kind { // Disallow ANY unconstrained type parameters. ty::GenericParamDefKind::Type { .. } => { diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index be1be1a135407..6dd59a62a7a46 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -212,7 +212,7 @@ fn get_impl_args( traits::ObligationCause::new( impl1_span, impl1_def_id, - traits::ObligationCauseCode::BindingObligation(impl2_node.def_id(), span), + traits::ObligationCauseCode::WhereClause(impl2_node.def_id(), span), ) }, ); diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 66b86c9eb02a3..e75740837f8d4 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -184,7 +184,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { let def_kind = tcx.def_kind(item_def_id); match def_kind { DefKind::Static { .. } => tcx.ensure().eval_static_initializer(item_def_id), - DefKind::Const if tcx.generics_of(item_def_id).params.is_empty() => { + DefKind::Const if tcx.generics_of(item_def_id).own_params.is_empty() => { let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty()); let cid = GlobalId { instance, promoted: None }; let param_env = ty::ParamEnv::reveal_all(); diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs index dcab571eedf56..9ddba7a6e7a9b 100644 --- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs @@ -421,7 +421,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { // We could not gather enough lifetime parameters in the scope. // We use the parameter names from the target type's definition instead. self.gen_params - .params + .own_params .iter() .skip(self.params_offset + self.num_provided_lifetime_args()) .take(num_params_to_take) @@ -464,7 +464,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { }) }; self.gen_params - .params + .own_params .iter() .skip(self.params_offset + self.num_provided_type_or_const_args()) .take(num_params_to_take) @@ -1076,7 +1076,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } else { let params = self .gen_params - .params + .own_params .iter() .skip(self.params_offset) .take(bound) diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 42885b0c83282..27fdea01c2b27 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -133,7 +133,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc let mut generics = generics; while let Some(def_id) = generics.parent { generics = tcx.generics_of(def_id); - for param in &generics.params { + for param in &generics.own_params { match param.kind { ty::GenericParamDefKind::Lifetime => { variances[param.index as usize] = ty::Bivariant; diff --git a/compiler/rustc_hir_analysis/src/variance/solve.rs b/compiler/rustc_hir_analysis/src/variance/solve.rs index 54da327702675..e64c6721fe018 100644 --- a/compiler/rustc_hir_analysis/src/variance/solve.rs +++ b/compiler/rustc_hir_analysis/src/variance/solve.rs @@ -76,7 +76,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { let tcx = self.terms_cx.tcx; // Make all const parameters invariant. - for param in generics.params.iter() { + for param in generics.own_params.iter() { if let ty::GenericParamDefKind::Const { .. } = param.kind { variances[param.index as usize] = ty::Invariant; } diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 0560d0d902a3f..72b95a9603dd0 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -46,10 +46,6 @@ hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which implements `is_empty` -hir_typeck_dereferencing_mut_binding = dereferencing `mut` binding - .label = `mut` dereferences the type of this binding - .help = this will change in edition 2024 - hir_typeck_expected_default_return_type = expected `()` because of default return type hir_typeck_expected_return_type = expected `{$expected}` because of return type diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 4ff6678fc9144..c2e62e4c0035a 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -5,7 +5,6 @@ use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::LocalDefId; use rustc_hir::{self as hir, ExprKind, PatKind}; use rustc_hir_pretty::ty_to_string; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; use rustc_trait_selection::traits::{ @@ -67,7 +66,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // arm for inconsistent arms or to the whole match when a `()` type // is required). Expectation::ExpectHasType(ety) if ety != tcx.types.unit => ety, - _ => self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr.span }), + _ => self.next_ty_var(expr.span), }; CoerceMany::with_coercion_sites(coerce_first, arms) }; @@ -575,8 +574,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // ...but otherwise we want to use any supertype of the // scrutinee. This is sort of a workaround, see note (*) in // `check_pat` for some details. - let scrut_ty = - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: scrut.span }); + let scrut_ty = self.next_ty_var(scrut.span); self.check_expr_has_type_or_error(scrut, scrut_ty, |_| {}); scrut_ty } diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index dfd0b7c2945c4..defb557867b79 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -9,11 +9,11 @@ use rustc_hir as hir; use rustc_hir::def::{self, CtorKind, Namespace, Res}; use rustc_hir::def_id::DefId; use rustc_hir_analysis::autoderef::Autoderef; +use rustc_infer::traits::ObligationCauseCode; use rustc_infer::{ infer, - traits::{self, Obligation}, + traits::{self, Obligation, ObligationCause}, }; -use rustc_infer::{infer::type_variable::TypeVariableOrigin, traits::ObligationCause}; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; @@ -118,7 +118,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // we must check that return type of called functions is WF: - self.register_wf_obligation(output.into(), call_expr.span, traits::WellFormed(None)); + self.register_wf_obligation( + output.into(), + call_expr.span, + ObligationCauseCode::WellFormed(None), + ); output } @@ -180,14 +184,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { infer::FnCall, closure_args.coroutine_closure_sig(), ); - let tupled_upvars_ty = self - .next_ty_var(TypeVariableOrigin { param_def_id: None, span: callee_expr.span }); + let tupled_upvars_ty = self.next_ty_var(callee_expr.span); // We may actually receive a coroutine back whose kind is different // from the closure that this dispatched from. This is because when // we have no captures, we automatically implement `FnOnce`. This // impl forces the closure kind to `FnOnce` i.e. `u8`. - let kind_ty = self - .next_ty_var(TypeVariableOrigin { param_def_id: None, span: callee_expr.span }); + let kind_ty = self.next_ty_var(callee_expr.span); let call_sig = self.tcx.mk_fn_sig( [coroutine_closure_sig.tupled_inputs_ty], coroutine_closure_sig.to_coroutine( @@ -298,12 +300,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let Some(trait_def_id) = opt_trait_def_id else { continue }; let opt_input_type = opt_arg_exprs.map(|arg_exprs| { - Ty::new_tup_from_iter( - self.tcx, - arg_exprs.iter().map(|e| { - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: e.span }) - }), - ) + Ty::new_tup_from_iter(self.tcx, arg_exprs.iter().map(|e| self.next_ty_var(e.span))) }); if let Some(ok) = self.lookup_method_in_trait( @@ -532,9 +529,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_bound( ty, self.tcx.require_lang_item(hir::LangItem::Tuple, Some(sp)), - traits::ObligationCause::new(sp, self.body_id, traits::RustCall), + traits::ObligationCause::new(sp, self.body_id, ObligationCauseCode::RustCall), ); - self.require_type_is_sized(ty, sp, traits::RustCall); + self.require_type_is_sized(ty, sp, ObligationCauseCode::RustCall); } else { self.dcx().emit_err(errors::RustCallIncorrectArgs { span: sp }); } diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index b106eca59c473..89e64cf5f0d98 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -8,14 +8,12 @@ use rustc_hir::def::DefKind; use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir_analysis::check::{check_function_signature, forbid_intrinsic_abi}; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::RegionVariableOrigin; use rustc_infer::traits::WellFormedLoc; use rustc_middle::ty::{self, Binder, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::sym; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::traits; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; /// Helper used for fns and closures. Does the grungy work of checking a function @@ -77,7 +75,7 @@ pub(super) fn check_fn<'a, 'tcx>( fcx.register_wf_obligation( param_ty.into(), param.span, - traits::WellFormed(Some(WellFormedLoc::Param { + ObligationCauseCode::WellFormed(Some(WellFormedLoc::Param { function: fn_def_id, param_idx: idx, })), @@ -102,7 +100,7 @@ pub(super) fn check_fn<'a, 'tcx>( param.pat.span, // ty.span == binding_span iff this is a closure parameter with no type ascription, // or if it's an implicit `self` parameter - traits::SizedArgumentType( + ObligationCauseCode::SizedArgumentType( if ty_span == Some(param.span) && tcx.is_closure_like(fn_def_id.into()) { None } else { @@ -122,10 +120,18 @@ pub(super) fn check_fn<'a, 'tcx>( hir::FnRetTy::Return(ty) => ty.span, }; - fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::SizedReturnType); + fcx.require_type_is_sized( + declared_ret_ty, + return_or_body_span, + ObligationCauseCode::SizedReturnType, + ); // We checked the root's signature during wfcheck, but not the child. if fcx.tcx.is_typeck_child(fn_def_id.to_def_id()) { - fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::WellFormed(None)); + fcx.require_type_is_sized( + declared_ret_ty, + return_or_body_span, + ObligationCauseCode::WellFormed(None), + ); } fcx.is_whole_body.set(true); @@ -142,7 +148,7 @@ pub(super) fn check_fn<'a, 'tcx>( // We have special-cased the case where the function is declared // `-> dyn Foo` and we don't actually relate it to the // `fcx.ret_coercion`, so just instantiate a type variable. - actual_return_ty = fcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span }); + actual_return_ty = fcx.next_ty_var(span); debug!("actual_return_ty replaced with {:?}", actual_return_ty); } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 4883c7aff8bc4..f52f95db6d342 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -6,9 +6,9 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes}; use rustc_infer::infer::{InferOk, InferResult}; +use rustc_infer::traits::ObligationCauseCode; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::GenericArgs; @@ -31,6 +31,7 @@ struct ExpectedSig<'tcx> { sig: ty::PolyFnSig<'tcx>, } +#[derive(Debug)] struct ClosureSignatures<'tcx> { /// The signature users of the closure see. bound_sig: ty::PolyFnSig<'tcx>, @@ -72,8 +73,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let parent_args = GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id())); - let tupled_upvars_ty = - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span }); + let tupled_upvars_ty = self.next_ty_var(expr_span); // FIXME: We could probably actually just unify this further -- // instead of having a `FnSig` and a `Option`, @@ -100,9 +100,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Create a type variable (for now) to represent the closure kind. // It will be unified during the upvar inference phase (`upvar.rs`) - None => { - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span }) - } + None => self.next_ty_var(expr_span), }; let closure_args = ty::ClosureArgs::new( @@ -121,11 +119,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let yield_ty = match kind { hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _) | hir::CoroutineKind::Coroutine(_) => { - let yield_ty = self.next_ty_var(TypeVariableOrigin { - param_def_id: None, - span: expr_span, - }); - self.require_type_is_sized(yield_ty, expr_span, traits::SizedYieldType); + let yield_ty = self.next_ty_var(expr_span); + self.require_type_is_sized( + yield_ty, + expr_span, + ObligationCauseCode::SizedYieldType, + ); yield_ty } // HACK(-Ztrait-solver=next): In the *old* trait solver, we must eagerly @@ -133,11 +132,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // in this block in projection correctly. In the new trait solver, it is // not a problem. hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => { - let yield_ty = self.next_ty_var(TypeVariableOrigin { - param_def_id: None, - span: expr_span, - }); - self.require_type_is_sized(yield_ty, expr_span, traits::SizedYieldType); + let yield_ty = self.next_ty_var(expr_span); + self.require_type_is_sized( + yield_ty, + expr_span, + ObligationCauseCode::SizedYieldType, + ); Ty::new_adt( tcx, @@ -162,8 +162,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Resume type defaults to `()` if the coroutine has no argument. let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit); - let interior = - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span }); + let interior = self.next_ty_var(expr_span); self.deferred_coroutine_interiors.borrow_mut().push(( expr_def_id, body.id(), @@ -176,7 +175,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // ty of `().` let kind_ty = match kind { hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure) => { - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span }) + self.next_ty_var(expr_span) } _ => tcx.types.unit, }; @@ -211,23 +210,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; // Compute all of the variables that will be used to populate the coroutine. - let resume_ty = - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span }); - let interior = - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span }); + let resume_ty = self.next_ty_var(expr_span); + let interior = self.next_ty_var(expr_span); let closure_kind_ty = match expected_kind { Some(kind) => Ty::from_closure_kind(tcx, kind), // Create a type variable (for now) to represent the closure kind. // It will be unified during the upvar inference phase (`upvar.rs`) - None => { - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span }) - } + None => self.next_ty_var(expr_span), }; - let coroutine_captures_by_ref_ty = - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span }); + let coroutine_captures_by_ref_ty = self.next_ty_var(expr_span); let closure_args = ty::CoroutineClosureArgs::new( tcx, ty::CoroutineClosureArgsParts { @@ -259,13 +253,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Create a type variable (for now) to represent the closure kind. // It will be unified during the upvar inference phase (`upvar.rs`) - None => { - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span }) - } + None => self.next_ty_var(expr_span), }; - let coroutine_upvars_ty = - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span }); + let coroutine_upvars_ty = self.next_ty_var(expr_span); // We need to turn the liberated signature that we got from HIR, which // looks something like `|Args...| -> T`, into a signature that is suitable @@ -713,25 +704,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // [c2]: https://github.com/rust-lang/rust/pull/45072#issuecomment-341096796 self.commit_if_ok(|_| { let mut all_obligations = vec![]; - let inputs: Vec<_> = iter::zip( - decl.inputs, - supplied_sig.inputs().skip_binder(), // binder moved to (*) below - ) - .map(|(hir_ty, &supplied_ty)| { - // Instantiate (this part of..) S to S', i.e., with fresh variables. - self.instantiate_binder_with_fresh_vars( - hir_ty.span, - BoundRegionConversionTime::FnCall, - // (*) binder moved to here - supplied_sig.inputs().rebind(supplied_ty), - ) - }) - .collect(); + let supplied_sig = self.instantiate_binder_with_fresh_vars( + self.tcx.def_span(expr_def_id), + BoundRegionConversionTime::FnCall, + supplied_sig, + ); // The liberated version of this signature should be a subtype // of the liberated form of the expectation. for ((hir_ty, &supplied_ty), expected_ty) in iter::zip( - iter::zip(decl.inputs, &inputs), + iter::zip(decl.inputs, supplied_sig.inputs()), expected_sigs.liberated_sig.inputs(), // `liberated_sig` is E'. ) { // Check that E' = S'. @@ -744,11 +726,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { all_obligations.extend(obligations); } - let supplied_output_ty = self.instantiate_binder_with_fresh_vars( - decl.output.span(), - BoundRegionConversionTime::FnCall, - supplied_sig.output(), - ); + let supplied_output_ty = supplied_sig.output(); let cause = &self.misc(decl.output.span()); let InferOk { value: (), obligations } = self.at(cause, self.param_env).eq( DefineOpaqueTypes::Yes, @@ -757,7 +735,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )?; all_obligations.extend(obligations); - let inputs = inputs.into_iter().map(|ty| self.resolve_vars_if_possible(ty)); + let inputs = + supplied_sig.inputs().into_iter().map(|&ty| self.resolve_vars_if_possible(ty)); expected_sigs.liberated_sig = self.tcx.mk_fn_sig( inputs, @@ -1013,6 +992,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { result } + #[instrument(level = "debug", skip(self), ret)] fn closure_sigs( &self, expr_def_id: LocalDefId, diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index df92af876f612..88ba937e4b5bc 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -41,7 +41,6 @@ use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; use rustc_infer::traits::{IfExpressionCause, MatchExpressionArmCause}; use rustc_infer::traits::{Obligation, PredicateObligation}; @@ -257,11 +256,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { if b.is_ty_var() { // Two unresolved type variables: create a `Coerce` predicate. - let target_ty = if self.use_lub { - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: self.cause.span }) - } else { - b - }; + let target_ty = if self.use_lub { self.next_ty_var(self.cause.span) } else { b }; let mut obligations = Vec::with_capacity(2); for &source_ty in &[a, b] { @@ -557,8 +552,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // the `CoerceUnsized` target type and the expected type. // We only have the latter, so we use an inference variable // for the former and let type inference do the rest. - let origin = TypeVariableOrigin { param_def_id: None, span: self.cause.span }; - let coerce_target = self.next_ty_var(origin); + let coerce_target = self.next_ty_var(self.cause.span); let mut coercion = self.unify_and(coerce_target, target, |target| { let unsize = Adjustment { kind: Adjust::Pointer(PointerCoercion::Unsize), target }; match reborrow { @@ -764,10 +758,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { self.tcx, self.cause.clone(), self.param_env, - ty::TraitRef::from_lang_item( + ty::TraitRef::new( self.tcx, - hir::LangItem::PointerLike, - self.cause.span, + self.tcx.require_lang_item(hir::LangItem::PointerLike, Some(self.cause.span)), [a], ), )); diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 60c0b1872fa03..b211249173324 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -330,16 +330,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir.body(hir.maybe_body_owned_by(self.body_id).expect("expected item to have body")); expr_finder.visit_expr(body.value); - use rustc_infer::infer::type_variable::*; - use rustc_middle::infer::unify_key::*; // Replaces all of the variables in the given type with a fresh inference variable. let mut fudger = BottomUpFolder { tcx: self.tcx, ty_op: |ty| { if let ty::Infer(infer) = ty.kind() { match infer { - ty::TyVar(_) => self - .next_ty_var(TypeVariableOrigin { param_def_id: None, span: DUMMY_SP }), + ty::TyVar(_) => self.next_ty_var(DUMMY_SP), ty::IntVar(_) => self.next_int_var(), ty::FloatVar(_) => self.next_float_var(), ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => { @@ -353,10 +350,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lt_op: |_| self.tcx.lifetimes.re_erased, ct_op: |ct| { if let ty::ConstKind::Infer(_) = ct.kind() { - self.next_const_var( - ct.ty(), - ConstVariableOrigin { param_def_id: None, span: DUMMY_SP }, - ) + self.next_const_var(ct.ty(), DUMMY_SP) } else { ct } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index ba8f246fd8d24..f250b909596ea 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -651,10 +651,3 @@ pub enum SuggestBoxingForReturnImplTrait { ends: Vec, }, } -#[derive(LintDiagnostic)] -#[diag(hir_typeck_dereferencing_mut_binding)] -pub struct DereferencingMutBinding { - #[label] - #[help] - pub span: Span, -} diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs index 5106d29091a17..91deae4174b00 100644 --- a/compiler/rustc_hir_typeck/src/expectation.rs +++ b/compiler/rustc_hir_typeck/src/expectation.rs @@ -1,4 +1,3 @@ -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; @@ -110,7 +109,6 @@ impl<'a, 'tcx> Expectation<'tcx> { /// Like `only_has_type`, but instead of returning `None` if no /// hard constraint exists, creates a fresh type variable. pub(super) fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> { - self.only_has_type(fcx) - .unwrap_or_else(|| fcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span })) + self.only_has_type(fcx).unwrap_or_else(|| fcx.next_ty_var(span)) } } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 7b552bb707743..cdf17f3a1131c 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -37,7 +37,6 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, HirId, QPath}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _; use rustc_infer::infer; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::InferOk; use rustc_infer::traits::query::NoSolution; @@ -80,8 +79,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Ty::new_error(self.tcx(), reported); } - let adj_ty = - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr.span }); + let adj_ty = self.next_ty_var(expr.span); self.apply_adjustments( expr, vec![Adjustment { kind: Adjust::NeverToAny, target: adj_ty }], @@ -575,7 +573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.require_type_is_sized_deferred( input, span, - traits::SizedArgumentType(None), + ObligationCauseCode::SizedArgumentType(None), ); } } @@ -593,7 +591,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.require_type_is_sized_deferred( output, call.map_or(expr.span, |e| e.span), - traits::SizedCallReturnType, + ObligationCauseCode::SizedCallReturnType, ); } @@ -1251,7 +1249,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }); - self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized); + self.require_type_is_sized(lhs_ty, lhs.span, ObligationCauseCode::AssignmentLhsSized); if let Err(guar) = (lhs_ty, rhs_ty).error_reported() { Ty::new_error(self.tcx, guar) @@ -1271,7 +1269,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // otherwise check exactly as a let statement self.check_decl((let_expr, hir_id).into()); // but return a bool, for this is a boolean expression - if let Some(error_guaranteed) = let_expr.is_recovered { + if let ast::Recovered::Yes(error_guaranteed) = let_expr.recovered { self.set_tainted_by_errors(error_guaranteed); Ty::new_error(self.tcx, error_guaranteed) } else { @@ -1412,9 +1410,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Array(ty, _) | ty::Slice(ty) => Some(ty), _ => None, }) - .unwrap_or_else(|| { - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr.span }) - }); + .unwrap_or_else(|| self.next_ty_var(expr.span)); let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args); assert_eq!(self.diverges.get(), Diverges::Maybe); for e in args { @@ -1424,7 +1420,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } coerce.complete(self) } else { - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr.span }) + self.next_ty_var(expr.span) }; let array_len = args.len() as u64; self.suggest_array_len(expr, array_len); @@ -1475,7 +1471,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { crate::GatherLocalsVisitor::new(&fcx).visit_body(body); let ty = fcx.check_expr_with_expectation(body.value, expected); - fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized); + fcx.require_type_is_sized(ty, body.value.span, ObligationCauseCode::ConstSized); fcx.write_ty(block.hir_id, ty); ty } @@ -1507,8 +1503,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (uty, uty) } None => { - let ty = - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: element.span }); + let ty = self.next_ty_var(element.span); let element_ty = self.check_expr_has_type_or_error(element, ty, |_| {}); (element_ty, ty) } @@ -1522,7 +1517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = Ty::new_array_with_const_len(tcx, t, count); - self.register_wf_obligation(ty.into(), expr.span, traits::WellFormed(None)); + self.register_wf_obligation(ty.into(), expr.span, ObligationCauseCode::WellFormed(None)); ty } @@ -1612,7 +1607,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Err(guar) = tuple.error_reported() { Ty::new_error(self.tcx, guar) } else { - self.require_type_is_sized(tuple, expr.span, traits::TupleInitializerSized); + self.require_type_is_sized( + tuple, + expr.span, + ObligationCauseCode::TupleInitializerSized, + ); tuple } } @@ -1651,7 +1650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base_expr, ); - self.require_type_is_sized(adt_ty, expr.span, traits::StructInitializerSized); + self.require_type_is_sized(adt_ty, expr.span, ObligationCauseCode::StructInitializerSized); adt_ty } @@ -3084,14 +3083,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { polarity: ty::PredicatePolarity::Positive, }), |derived| { - traits::ImplDerivedObligation(Box::new( - traits::ImplDerivedObligationCause { - derived, - impl_or_alias_def_id: impl_def_id, - impl_def_predicate_index: Some(idx), - span, - }, - )) + ObligationCauseCode::ImplDerived(Box::new(traits::ImplDerivedCause { + derived, + impl_or_alias_def_id: impl_def_id, + impl_def_predicate_index: Some(idx), + span, + })) }, ) }, @@ -3182,7 +3179,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_expr_asm_operand(&self, expr: &'tcx hir::Expr<'tcx>, is_input: bool) { let needs = if is_input { Needs::None } else { Needs::MutPlace }; let ty = self.check_expr_with_needs(expr, needs); - self.require_type_is_sized(ty, expr.span, traits::InlineAsmSized); + self.require_type_is_sized(ty, expr.span, ObligationCauseCode::InlineAsmSized); if !is_input && !expr.is_syntactic_place_expr() { self.dcx() @@ -3353,7 +3350,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let field_ty = self.field_ty(expr.span, field, args); // FIXME: DSTs with static alignment should be allowed - self.require_type_is_sized(field_ty, expr.span, traits::MiscObligation); + self.require_type_is_sized(field_ty, expr.span, ObligationCauseCode::Misc); if field.vis.is_accessible_from(sub_def_scope, self.tcx) { self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None); @@ -3381,7 +3378,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let field_ty = self.field_ty(expr.span, field, args); // FIXME: DSTs with static alignment should be allowed - self.require_type_is_sized(field_ty, expr.span, traits::MiscObligation); + self.require_type_is_sized(field_ty, expr.span, ObligationCauseCode::Misc); if field.vis.is_accessible_from(def_scope, self.tcx) { self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None); @@ -3402,7 +3399,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && field.name == sym::integer(index) { for ty in tys.iter().take(index + 1) { - self.require_type_is_sized(ty, expr.span, traits::MiscObligation); + self.require_type_is_sized(ty, expr.span, ObligationCauseCode::Misc); } if let Some(&field_ty) = tys.get(index) { field_indices.push((FIRST_VARIANT, index.into())); diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index cc42e69f53827..589f41948defb 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -2,26 +2,33 @@ //! normal visitor, which just walks the entire body in one shot, the //! `ExprUseVisitor` determines how expressions are being used. +use std::cell::{Ref, RefCell}; +use std::ops::Deref; use std::slice::from_ref; use hir::def::DefKind; +use hir::pat_util::EnumerateAndAdjustIterator as _; use hir::Expr; +use rustc_lint::LateContext; // Export these here so that Clippy can use them. pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection}; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; -use rustc_hir::def::Res; +use rustc_hir::def::{CtorOf, Res}; use rustc_hir::def_id::LocalDefId; use rustc_hir::{HirId, PatKind}; -use rustc_infer::infer::InferCtxt; use rustc_middle::hir::place::ProjectionKind; use rustc_middle::mir::FakeReadCause; -use rustc_middle::ty::{self, adjustment, AdtKind, Ty, TyCtxt}; -use rustc_target::abi::FIRST_VARIANT; +use rustc_middle::ty::{ + self, adjustment, AdtKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _, +}; +use rustc_span::{ErrorGuaranteed, Span}; +use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; +use rustc_trait_selection::infer::InferCtxtExt; use ty::BorrowKind::ImmBorrow; -use crate::mem_categorization as mc; +use crate::fn_ctxt::FnCtxt; /// This trait defines the callbacks you can expect to receive when /// employing the ExprUseVisitor. @@ -80,191 +87,322 @@ pub trait Delegate<'tcx> { ); } -#[derive(Copy, Clone, PartialEq, Debug)] -enum ConsumeMode { - /// reference to x where x has a type that copies - Copy, - /// reference to x where x has a type that moves - Move, +impl<'tcx, D: Delegate<'tcx>> Delegate<'tcx> for &mut D { + fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { + (**self).consume(place_with_id, diag_expr_id) + } + + fn borrow( + &mut self, + place_with_id: &PlaceWithHirId<'tcx>, + diag_expr_id: HirId, + bk: ty::BorrowKind, + ) { + (**self).borrow(place_with_id, diag_expr_id, bk) + } + + fn copy(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { + (**self).copy(place_with_id, diag_expr_id) + } + + fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { + (**self).mutate(assignee_place, diag_expr_id) + } + + fn bind(&mut self, binding_place: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { + (**self).bind(binding_place, diag_expr_id) + } + + fn fake_read( + &mut self, + place_with_id: &PlaceWithHirId<'tcx>, + cause: FakeReadCause, + diag_expr_id: HirId, + ) { + (**self).fake_read(place_with_id, cause, diag_expr_id) + } +} + +pub trait TypeInformationCtxt<'tcx> { + type TypeckResults<'a>: Deref> + where + Self: 'a; + + type Error; + + fn typeck_results(&self) -> Self::TypeckResults<'_>; + + fn resolve_vars_if_possible>>(&self, t: T) -> T; + + fn try_structurally_resolve_type(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>; + + fn report_error(&self, span: Span, msg: impl ToString) -> Self::Error; + + fn error_reported_in_ty(&self, ty: Ty<'tcx>) -> Result<(), Self::Error>; + + fn tainted_by_errors(&self) -> Result<(), Self::Error>; + + fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool; + + fn body_owner_def_id(&self) -> LocalDefId; + + fn tcx(&self) -> TyCtxt<'tcx>; +} + +impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> { + type TypeckResults<'a> = Ref<'a, ty::TypeckResults<'tcx>> + where + Self: 'a; + + type Error = ErrorGuaranteed; + + fn typeck_results(&self) -> Self::TypeckResults<'_> { + self.typeck_results.borrow() + } + + fn resolve_vars_if_possible>>(&self, t: T) -> T { + self.infcx.resolve_vars_if_possible(t) + } + + fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + (**self).try_structurally_resolve_type(sp, ty) + } + + fn report_error(&self, span: Span, msg: impl ToString) -> Self::Error { + self.tcx.dcx().span_delayed_bug(span, msg.to_string()) + } + + fn error_reported_in_ty(&self, ty: Ty<'tcx>) -> Result<(), Self::Error> { + ty.error_reported() + } + + fn tainted_by_errors(&self) -> Result<(), ErrorGuaranteed> { + if let Some(guar) = self.infcx.tainted_by_errors() { Err(guar) } else { Ok(()) } + } + + fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool { + self.infcx.type_is_copy_modulo_regions(self.param_env, ty) + } + + fn body_owner_def_id(&self) -> LocalDefId { + self.body_id + } + + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } +} + +impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) { + type TypeckResults<'a> = &'tcx ty::TypeckResults<'tcx> + where + Self: 'a; + + type Error = !; + + fn typeck_results(&self) -> Self::TypeckResults<'_> { + self.0.maybe_typeck_results().expect("expected typeck results") + } + + fn try_structurally_resolve_type(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + // FIXME: Maybe need to normalize here. + ty + } + + fn resolve_vars_if_possible>>(&self, t: T) -> T { + t + } + + fn report_error(&self, span: Span, msg: impl ToString) -> ! { + span_bug!(span, "{}", msg.to_string()) + } + + fn error_reported_in_ty(&self, _ty: Ty<'tcx>) -> Result<(), !> { + Ok(()) + } + + fn tainted_by_errors(&self) -> Result<(), !> { + Ok(()) + } + + fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool { + ty.is_copy_modulo_regions(self.0.tcx, self.0.param_env) + } + + fn body_owner_def_id(&self) -> LocalDefId { + self.1 + } + + fn tcx(&self) -> TyCtxt<'tcx> { + self.0.tcx + } } /// The ExprUseVisitor type /// /// This is the code that actually walks the tree. -pub struct ExprUseVisitor<'a, 'tcx> { - mc: mc::MemCategorizationContext<'a, 'tcx>, - body_owner: LocalDefId, - delegate: &'a mut dyn Delegate<'tcx>, +pub struct ExprUseVisitor<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> { + cx: Cx, + /// We use a `RefCell` here so that delegates can mutate themselves, but we can + /// still have calls to our own helper functions. + delegate: RefCell, + upvars: Option<&'tcx FxIndexMap>, } -/// If the MC results in an error, it's because the type check -/// failed (or will fail, when the error is uncovered and reported -/// during writeback). In this case, we just ignore this part of the -/// code. -/// -/// Note that this macro appears similar to try!(), but, unlike try!(), -/// it does not propagate the error. -macro_rules! return_if_err { - ($inp: expr) => { - match $inp { - Ok(v) => v, - Err(()) => { - debug!("mc reported err"); - return; - } - } - }; +impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'tcx, (&'a LateContext<'tcx>, LocalDefId), D> { + pub fn for_clippy(cx: &'a LateContext<'tcx>, body_def_id: LocalDefId, delegate: D) -> Self { + Self::new((cx, body_def_id), delegate) + } } -impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { +impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> { /// Creates the ExprUseVisitor, configuring it with the various options provided: /// /// - `delegate` -- who receives the callbacks /// - `param_env` --- parameter environment for trait lookups (esp. pertaining to `Copy`) /// - `typeck_results` --- typeck results for the code being analyzed - pub fn new( - delegate: &'a mut (dyn Delegate<'tcx> + 'a), - infcx: &'a InferCtxt<'tcx>, - body_owner: LocalDefId, - param_env: ty::ParamEnv<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, - ) -> Self { + pub(crate) fn new(cx: Cx, delegate: D) -> Self { ExprUseVisitor { - mc: mc::MemCategorizationContext::new(infcx, param_env, body_owner, typeck_results), - body_owner, - delegate, + delegate: RefCell::new(delegate), + upvars: cx.tcx().upvars_mentioned(cx.body_owner_def_id()), + cx, } } - #[instrument(skip(self), level = "debug")] - pub fn consume_body(&mut self, body: &hir::Body<'_>) { + pub fn consume_body(&self, body: &hir::Body<'_>) -> Result<(), Cx::Error> { for param in body.params { - let param_ty = return_if_err!(self.mc.pat_ty_adjusted(param.pat)); + let param_ty = self.pat_ty_adjusted(param.pat)?; debug!("consume_body: param_ty = {:?}", param_ty); - let param_place = self.mc.cat_rvalue(param.hir_id, param_ty); + let param_place = self.cat_rvalue(param.hir_id, param_ty); - self.walk_irrefutable_pat(¶m_place, param.pat); + self.walk_irrefutable_pat(¶m_place, param.pat)?; } - self.consume_expr(body.value); - } + self.consume_expr(body.value)?; - fn tcx(&self) -> TyCtxt<'tcx> { - self.mc.tcx() + Ok(()) } - fn delegate_consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { - delegate_consume(&self.mc, self.delegate, place_with_id, diag_expr_id) + fn consume_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { + debug!("delegate_consume(place_with_id={:?})", place_with_id); + + if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) { + self.delegate.borrow_mut().copy(place_with_id, diag_expr_id); + } else { + self.delegate.borrow_mut().consume(place_with_id, diag_expr_id); + } } - fn consume_exprs(&mut self, exprs: &[hir::Expr<'_>]) { + fn consume_exprs(&self, exprs: &[hir::Expr<'_>]) -> Result<(), Cx::Error> { for expr in exprs { - self.consume_expr(expr); + self.consume_expr(expr)?; } + + Ok(()) } - pub fn consume_expr(&mut self, expr: &hir::Expr<'_>) { + // FIXME: It's suspicious that this is public; clippy should probably use `walk_expr`. + pub fn consume_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> { debug!("consume_expr(expr={:?})", expr); - let place_with_id = return_if_err!(self.mc.cat_expr(expr)); - self.delegate_consume(&place_with_id, place_with_id.hir_id); - self.walk_expr(expr); + let place_with_id = self.cat_expr(expr)?; + self.consume_or_copy(&place_with_id, place_with_id.hir_id); + self.walk_expr(expr)?; + Ok(()) } - fn mutate_expr(&mut self, expr: &hir::Expr<'_>) { - let place_with_id = return_if_err!(self.mc.cat_expr(expr)); - self.delegate.mutate(&place_with_id, place_with_id.hir_id); - self.walk_expr(expr); + fn mutate_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> { + let place_with_id = self.cat_expr(expr)?; + self.delegate.borrow_mut().mutate(&place_with_id, place_with_id.hir_id); + self.walk_expr(expr)?; + Ok(()) } - fn borrow_expr(&mut self, expr: &hir::Expr<'_>, bk: ty::BorrowKind) { + fn borrow_expr(&self, expr: &hir::Expr<'_>, bk: ty::BorrowKind) -> Result<(), Cx::Error> { debug!("borrow_expr(expr={:?}, bk={:?})", expr, bk); - let place_with_id = return_if_err!(self.mc.cat_expr(expr)); - self.delegate.borrow(&place_with_id, place_with_id.hir_id, bk); - - self.walk_expr(expr) - } - - fn select_from_expr(&mut self, expr: &hir::Expr<'_>) { + let place_with_id = self.cat_expr(expr)?; + self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk); self.walk_expr(expr) } - pub fn walk_expr(&mut self, expr: &hir::Expr<'_>) { + pub fn walk_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> { debug!("walk_expr(expr={:?})", expr); - self.walk_adjustment(expr); + self.walk_adjustment(expr)?; match expr.kind { hir::ExprKind::Path(_) => {} - hir::ExprKind::Type(subexpr, _) => self.walk_expr(subexpr), + hir::ExprKind::Type(subexpr, _) => { + self.walk_expr(subexpr)?; + } hir::ExprKind::Unary(hir::UnOp::Deref, base) => { // *base - self.select_from_expr(base); + self.walk_expr(base)?; } hir::ExprKind::Field(base, _) => { // base.f - self.select_from_expr(base); + self.walk_expr(base)?; } hir::ExprKind::Index(lhs, rhs, _) => { // lhs[rhs] - self.select_from_expr(lhs); - self.consume_expr(rhs); + self.walk_expr(lhs)?; + self.consume_expr(rhs)?; } hir::ExprKind::Call(callee, args) => { // callee(args) - self.consume_expr(callee); - self.consume_exprs(args); + self.consume_expr(callee)?; + self.consume_exprs(args)?; } hir::ExprKind::MethodCall(.., receiver, args, _) => { // callee.m(args) - self.consume_expr(receiver); - self.consume_exprs(args); + self.consume_expr(receiver)?; + self.consume_exprs(args)?; } hir::ExprKind::Struct(_, fields, ref opt_with) => { - self.walk_struct_expr(fields, opt_with); + self.walk_struct_expr(fields, opt_with)?; } hir::ExprKind::Tup(exprs) => { - self.consume_exprs(exprs); + self.consume_exprs(exprs)?; } hir::ExprKind::If(cond_expr, then_expr, ref opt_else_expr) => { - self.consume_expr(cond_expr); - self.consume_expr(then_expr); + self.consume_expr(cond_expr)?; + self.consume_expr(then_expr)?; if let Some(else_expr) = *opt_else_expr { - self.consume_expr(else_expr); + self.consume_expr(else_expr)?; } } hir::ExprKind::Let(hir::LetExpr { pat, init, .. }) => { - self.walk_local(init, pat, None, |t| t.borrow_expr(init, ty::ImmBorrow)) + self.walk_local(init, pat, None, || self.borrow_expr(init, ty::ImmBorrow))?; } hir::ExprKind::Match(discr, arms, _) => { - let discr_place = return_if_err!(self.mc.cat_expr(discr)); - return_if_err!(self.maybe_read_scrutinee( + let discr_place = self.cat_expr(discr)?; + self.maybe_read_scrutinee( discr, discr_place.clone(), arms.iter().map(|arm| arm.pat), - )); + )?; // treatment of the discriminant is handled while walking the arms. for arm in arms { - self.walk_arm(&discr_place, arm); + self.walk_arm(&discr_place, arm)?; } } hir::ExprKind::Array(exprs) => { - self.consume_exprs(exprs); + self.consume_exprs(exprs)?; } hir::ExprKind::AddrOf(_, m, base) => { @@ -272,21 +410,23 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // make sure that the thing we are pointing out stays valid // for the lifetime `scope_r` of the resulting ptr: let bk = ty::BorrowKind::from_mutbl(m); - self.borrow_expr(base, bk); + self.borrow_expr(base, bk)?; } hir::ExprKind::InlineAsm(asm) => { for (op, _op_sp) in asm.operands { match op { - hir::InlineAsmOperand::In { expr, .. } => self.consume_expr(expr), + hir::InlineAsmOperand::In { expr, .. } => { + self.consume_expr(expr)?; + } hir::InlineAsmOperand::Out { expr: Some(expr), .. } | hir::InlineAsmOperand::InOut { expr, .. } => { - self.mutate_expr(expr); + self.mutate_expr(expr)?; } hir::InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => { - self.consume_expr(in_expr); + self.consume_expr(in_expr)?; if let Some(out_expr) = out_expr { - self.mutate_expr(out_expr); + self.mutate_expr(out_expr)?; } } hir::InlineAsmOperand::Out { expr: None, .. } @@ -294,7 +434,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { | hir::InlineAsmOperand::SymFn { .. } | hir::InlineAsmOperand::SymStatic { .. } => {} hir::InlineAsmOperand::Label { block } => { - self.walk_block(block); + self.walk_block(block)?; } } } @@ -307,72 +447,74 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { | hir::ExprKind::Err(_) => {} hir::ExprKind::Loop(blk, ..) => { - self.walk_block(blk); + self.walk_block(blk)?; } hir::ExprKind::Unary(_, lhs) => { - self.consume_expr(lhs); + self.consume_expr(lhs)?; } hir::ExprKind::Binary(_, lhs, rhs) => { - self.consume_expr(lhs); - self.consume_expr(rhs); + self.consume_expr(lhs)?; + self.consume_expr(rhs)?; } hir::ExprKind::Block(blk, _) => { - self.walk_block(blk); + self.walk_block(blk)?; } hir::ExprKind::Break(_, ref opt_expr) | hir::ExprKind::Ret(ref opt_expr) => { if let Some(expr) = *opt_expr { - self.consume_expr(expr); + self.consume_expr(expr)?; } } hir::ExprKind::Become(call) => { - self.consume_expr(call); + self.consume_expr(call)?; } hir::ExprKind::Assign(lhs, rhs, _) => { - self.mutate_expr(lhs); - self.consume_expr(rhs); + self.mutate_expr(lhs)?; + self.consume_expr(rhs)?; } hir::ExprKind::Cast(base, _) => { - self.consume_expr(base); + self.consume_expr(base)?; } hir::ExprKind::DropTemps(expr) => { - self.consume_expr(expr); + self.consume_expr(expr)?; } hir::ExprKind::AssignOp(_, lhs, rhs) => { - if self.mc.typeck_results.is_method_call(expr) { - self.consume_expr(lhs); + if self.cx.typeck_results().is_method_call(expr) { + self.consume_expr(lhs)?; } else { - self.mutate_expr(lhs); + self.mutate_expr(lhs)?; } - self.consume_expr(rhs); + self.consume_expr(rhs)?; } hir::ExprKind::Repeat(base, _) => { - self.consume_expr(base); + self.consume_expr(base)?; } hir::ExprKind::Closure(closure) => { - self.walk_captures(closure); + self.walk_captures(closure)?; } hir::ExprKind::Yield(value, _) => { - self.consume_expr(value); + self.consume_expr(value)?; } } + + Ok(()) } - fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) { + fn walk_stmt(&self, stmt: &hir::Stmt<'_>) -> Result<(), Cx::Error> { match stmt.kind { hir::StmtKind::Let(hir::LetStmt { pat, init: Some(expr), els, .. }) => { - self.walk_local(expr, pat, *els, |_| {}) + self.walk_local(expr, pat, *els, || Ok(()))?; } hir::StmtKind::Let(_) => {} @@ -383,25 +525,26 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr) => { - self.consume_expr(expr); + self.consume_expr(expr)?; } } + + Ok(()) } fn maybe_read_scrutinee<'t>( - &mut self, + &self, discr: &Expr<'_>, discr_place: PlaceWithHirId<'tcx>, pats: impl Iterator>, - ) -> Result<(), ()> { + ) -> Result<(), Cx::Error> { // Matching should not always be considered a use of the place, hence // discr does not necessarily need to be borrowed. // We only want to borrow discr if the pattern contain something other // than wildcards. - let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self; let mut needs_to_be_read = false; for pat in pats { - mc.cat_pattern(discr_place.clone(), pat, |place, pat| { + self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| { match &pat.kind { PatKind::Binding(.., opt_sub_pat) => { // If the opt_sub_pat is None, then the binding does not count as @@ -419,7 +562,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // A `Path` pattern is just a name like `Foo`. This is either a // named constant or else it refers to an ADT variant - let res = self.mc.typeck_results.qpath_res(qpath, pat.hir_id); + let res = self.cx.typeck_results().qpath_res(qpath, pat.hir_id); match res { Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => { // Named constants have to be equated with the value @@ -431,7 +574,8 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { _ => { // Otherwise, this is a struct/enum variant, and so it's // only a read if we need to read the discriminant. - needs_to_be_read |= is_multivariant_adt(place.place.ty()); + needs_to_be_read |= + self.is_multivariant_adt(place.place.ty(), pat.span); } } } @@ -443,7 +587,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // perform some reads). let place_ty = place.place.ty(); - needs_to_be_read |= is_multivariant_adt(place_ty); + needs_to_be_read |= self.is_multivariant_adt(place_ty, pat.span); } PatKind::Lit(_) | PatKind::Range(..) => { // If the PatKind is a Lit or a Range then we want @@ -473,18 +617,20 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // being examined } } + + Ok(()) })? } if needs_to_be_read { - self.borrow_expr(discr, ty::ImmBorrow); + self.borrow_expr(discr, ty::ImmBorrow)?; } else { let closure_def_id = match discr_place.place.base { PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id), _ => None, }; - self.delegate.fake_read( + self.delegate.borrow_mut().fake_read( &discr_place, FakeReadCause::ForMatchedPlace(closure_def_id), discr_place.hir_id, @@ -492,90 +638,93 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // We always want to walk the discriminant. We want to make sure, for instance, // that the discriminant has been initialized. - self.walk_expr(discr); + self.walk_expr(discr)?; } Ok(()) } fn walk_local( - &mut self, + &self, expr: &hir::Expr<'_>, pat: &hir::Pat<'_>, els: Option<&hir::Block<'_>>, mut f: F, - ) where - F: FnMut(&mut Self), + ) -> Result<(), Cx::Error> + where + F: FnMut() -> Result<(), Cx::Error>, { - self.walk_expr(expr); - let expr_place = return_if_err!(self.mc.cat_expr(expr)); - f(self); + self.walk_expr(expr)?; + let expr_place = self.cat_expr(expr)?; + f()?; if let Some(els) = els { // borrowing because we need to test the discriminant - return_if_err!(self.maybe_read_scrutinee( - expr, - expr_place.clone(), - from_ref(pat).iter() - )); - self.walk_block(els) + self.maybe_read_scrutinee(expr, expr_place.clone(), from_ref(pat).iter())?; + self.walk_block(els)?; } - self.walk_irrefutable_pat(&expr_place, pat); + self.walk_irrefutable_pat(&expr_place, pat)?; + Ok(()) } /// Indicates that the value of `blk` will be consumed, meaning either copied or moved /// depending on its type. - fn walk_block(&mut self, blk: &hir::Block<'_>) { + fn walk_block(&self, blk: &hir::Block<'_>) -> Result<(), Cx::Error> { debug!("walk_block(blk.hir_id={})", blk.hir_id); for stmt in blk.stmts { - self.walk_stmt(stmt); + self.walk_stmt(stmt)?; } if let Some(tail_expr) = blk.expr { - self.consume_expr(tail_expr); + self.consume_expr(tail_expr)?; } + + Ok(()) } fn walk_struct_expr<'hir>( - &mut self, + &self, fields: &[hir::ExprField<'_>], opt_with: &Option<&'hir hir::Expr<'_>>, - ) { + ) -> Result<(), Cx::Error> { // Consume the expressions supplying values for each field. for field in fields { - self.consume_expr(field.expr); + self.consume_expr(field.expr)?; // The struct path probably didn't resolve - if self.mc.typeck_results.opt_field_index(field.hir_id).is_none() { - self.tcx().dcx().span_delayed_bug(field.span, "couldn't resolve index for field"); + if self.cx.typeck_results().opt_field_index(field.hir_id).is_none() { + self.cx + .tcx() + .dcx() + .span_delayed_bug(field.span, "couldn't resolve index for field"); } } let with_expr = match *opt_with { Some(w) => &*w, None => { - return; + return Ok(()); } }; - let with_place = return_if_err!(self.mc.cat_expr(with_expr)); + let with_place = self.cat_expr(with_expr)?; // Select just those fields of the `with` // expression that will actually be used - match with_place.place.ty().kind() { + match self.cx.try_structurally_resolve_type(with_expr.span, with_place.place.ty()).kind() { ty::Adt(adt, args) if adt.is_struct() => { // Consume those fields of the with expression that are needed. for (f_index, with_field) in adt.non_enum_variant().fields.iter_enumerated() { - let is_mentioned = fields - .iter() - .any(|f| self.mc.typeck_results.opt_field_index(f.hir_id) == Some(f_index)); + let is_mentioned = fields.iter().any(|f| { + self.cx.typeck_results().opt_field_index(f.hir_id) == Some(f_index) + }); if !is_mentioned { - let field_place = self.mc.cat_projection( - &*with_expr, + let field_place = self.cat_projection( + with_expr.hir_id, with_place.clone(), - with_field.ty(self.tcx(), args), + with_field.ty(self.cx.tcx(), args), ProjectionKind::Field(f_index, FIRST_VARIANT), ); - self.delegate_consume(&field_place, field_place.hir_id); + self.consume_or_copy(&field_place, field_place.hir_id); } } } @@ -584,7 +733,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // struct; however, when EUV is run during typeck, it // may not. This will generate an error earlier in typeck, // so we can just ignore it. - if self.tcx().dcx().has_errors().is_none() { + if self.cx.tcx().dcx().has_errors().is_none() { span_bug!(with_expr.span, "with expression doesn't evaluate to a struct"); } } @@ -592,15 +741,18 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // walk the with expression so that complex expressions // are properly handled. - self.walk_expr(with_expr); + self.walk_expr(with_expr)?; + + Ok(()) } /// Invoke the appropriate delegate calls for anything that gets /// consumed or borrowed as part of the automatic adjustment /// process. - fn walk_adjustment(&mut self, expr: &hir::Expr<'_>) { - let adjustments = self.mc.typeck_results.expr_adjustments(expr); - let mut place_with_id = return_if_err!(self.mc.cat_expr_unadjusted(expr)); + fn walk_adjustment(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> { + let typeck_results = self.cx.typeck_results(); + let adjustments = typeck_results.expr_adjustments(expr); + let mut place_with_id = self.cat_expr_unadjusted(expr)?; for adjustment in adjustments { debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); match adjustment.kind { @@ -609,7 +761,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { | adjustment::Adjust::DynStar => { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. - self.delegate_consume(&place_with_id, place_with_id.hir_id); + self.consume_or_copy(&place_with_id, place_with_id.hir_id); } adjustment::Adjust::Deref(None) => {} @@ -621,23 +773,24 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // this is an autoref of `x`. adjustment::Adjust::Deref(Some(ref deref)) => { let bk = ty::BorrowKind::from_mutbl(deref.mutbl); - self.delegate.borrow(&place_with_id, place_with_id.hir_id, bk); + self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk); } adjustment::Adjust::Borrow(ref autoref) => { self.walk_autoref(expr, &place_with_id, autoref); } } - place_with_id = - return_if_err!(self.mc.cat_expr_adjusted(expr, place_with_id, adjustment)); + place_with_id = self.cat_expr_adjusted(expr, place_with_id, adjustment)?; } + + Ok(()) } /// Walks the autoref `autoref` applied to the autoderef'd /// `expr`. `base_place` is the mem-categorized form of `expr` /// after all relevant autoderefs have occurred. fn walk_autoref( - &mut self, + &self, expr: &hir::Expr<'_>, base_place: &PlaceWithHirId<'tcx>, autoref: &adjustment::AutoBorrow<'tcx>, @@ -649,7 +802,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { match *autoref { adjustment::AutoBorrow::Ref(_, m) => { - self.delegate.borrow( + self.delegate.borrow_mut().borrow( base_place, base_place.hir_id, ty::BorrowKind::from_mutbl(m.into()), @@ -659,80 +812,93 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { adjustment::AutoBorrow::RawPtr(m) => { debug!("walk_autoref: expr.hir_id={} base_place={:?}", expr.hir_id, base_place); - self.delegate.borrow(base_place, base_place.hir_id, ty::BorrowKind::from_mutbl(m)); + self.delegate.borrow_mut().borrow( + base_place, + base_place.hir_id, + ty::BorrowKind::from_mutbl(m), + ); } } } - fn walk_arm(&mut self, discr_place: &PlaceWithHirId<'tcx>, arm: &hir::Arm<'_>) { + fn walk_arm( + &self, + discr_place: &PlaceWithHirId<'tcx>, + arm: &hir::Arm<'_>, + ) -> Result<(), Cx::Error> { let closure_def_id = match discr_place.place.base { PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id), _ => None, }; - self.delegate.fake_read( + self.delegate.borrow_mut().fake_read( discr_place, FakeReadCause::ForMatchedPlace(closure_def_id), discr_place.hir_id, ); - self.walk_pat(discr_place, arm.pat, arm.guard.is_some()); + self.walk_pat(discr_place, arm.pat, arm.guard.is_some())?; if let Some(ref e) = arm.guard { - self.consume_expr(e) + self.consume_expr(e)?; } - self.consume_expr(arm.body); + self.consume_expr(arm.body)?; + Ok(()) } /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or /// let binding, and *not* a match arm or nested pat.) - fn walk_irrefutable_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) { + fn walk_irrefutable_pat( + &self, + discr_place: &PlaceWithHirId<'tcx>, + pat: &hir::Pat<'_>, + ) -> Result<(), Cx::Error> { let closure_def_id = match discr_place.place.base { PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id), _ => None, }; - self.delegate.fake_read( + self.delegate.borrow_mut().fake_read( discr_place, FakeReadCause::ForLet(closure_def_id), discr_place.hir_id, ); - self.walk_pat(discr_place, pat, false); + self.walk_pat(discr_place, pat, false)?; + Ok(()) } /// The core driver for walking a pattern fn walk_pat( - &mut self, + &self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>, has_guard: bool, - ) { + ) -> Result<(), Cx::Error> { debug!("walk_pat(discr_place={:?}, pat={:?}, has_guard={:?})", discr_place, pat, has_guard); - let tcx = self.tcx(); - let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self; - return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| { + let tcx = self.cx.tcx(); + self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| { if let PatKind::Binding(_, canonical_id, ..) = pat.kind { debug!("walk_pat: binding place={:?} pat={:?}", place, pat); if let Some(bm) = - mc.typeck_results.extract_binding_mode(tcx.sess, pat.hir_id, pat.span) + self.cx.typeck_results().extract_binding_mode(tcx.sess, pat.hir_id, pat.span) { debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); // pat_ty: the type of the binding being produced. - let pat_ty = return_if_err!(mc.node_ty(pat.hir_id)); + let pat_ty = self.node_ty(pat.hir_id)?; debug!("walk_pat: pat_ty={:?}", pat_ty); let def = Res::Local(canonical_id); - if let Ok(ref binding_place) = mc.cat_res(pat.hir_id, pat.span, pat_ty, def) { - delegate.bind(binding_place, binding_place.hir_id); + if let Ok(ref binding_place) = self.cat_res(pat.hir_id, pat.span, pat_ty, def) { + self.delegate.borrow_mut().bind(binding_place, binding_place.hir_id); } // Subtle: MIR desugaring introduces immutable borrows for each pattern // binding when lowering pattern guards to ensure that the guard does not // modify the scrutinee. if has_guard { - delegate.borrow(place, discr_place.hir_id, ImmBorrow); + self.delegate.borrow_mut().borrow(place, discr_place.hir_id, ImmBorrow); } // It is also a borrow or copy/move of the value being matched. @@ -742,11 +908,11 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { match bm.0 { hir::ByRef::Yes(m) => { let bk = ty::BorrowKind::from_mutbl(m); - delegate.borrow(place, discr_place.hir_id, bk); + self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk); } hir::ByRef::No => { debug!("walk_pat binding consuming pat"); - delegate_consume(mc, *delegate, place, discr_place.hir_id); + self.consume_or_copy(place, discr_place.hir_id); } } } @@ -755,12 +921,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // determines whether to borrow *at the level of the deref pattern* rather than // borrowing the bound place (since that inner place is inside the temporary that // stores the result of calling `deref()`/`deref_mut()` so can't be captured). - let mutable = mc.typeck_results.pat_has_ref_mut_binding(subpattern); + let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpattern); let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; let bk = ty::BorrowKind::from_mutbl(mutability); - delegate.borrow(place, discr_place.hir_id, bk); + self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk); } - })); + + Ok(()) + }) } /// Handle the case where the current body contains a closure. @@ -782,7 +950,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { /// /// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing /// closure as the DefId. - fn walk_captures(&mut self, closure_expr: &hir::Closure<'_>) { + fn walk_captures(&self, closure_expr: &hir::Closure<'_>) -> Result<(), Cx::Error> { fn upvar_is_local_variable( upvars: Option<&FxIndexMap>, upvar_id: HirId, @@ -793,21 +961,21 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { debug!("walk_captures({:?})", closure_expr); - let tcx = self.tcx(); + let tcx = self.cx.tcx(); let closure_def_id = closure_expr.def_id; - let upvars = tcx.upvars_mentioned(self.body_owner); - // For purposes of this function, coroutine and closures are equivalent. - let body_owner_is_closure = - matches!(tcx.hir().body_owner_kind(self.body_owner), hir::BodyOwnerKind::Closure,); + let body_owner_is_closure = matches!( + tcx.hir().body_owner_kind(self.cx.body_owner_def_id()), + hir::BodyOwnerKind::Closure + ); // If we have a nested closure, we want to include the fake reads present in the nested closure. - if let Some(fake_reads) = self.mc.typeck_results.closure_fake_reads.get(&closure_def_id) { + if let Some(fake_reads) = self.cx.typeck_results().closure_fake_reads.get(&closure_def_id) { for (fake_read, cause, hir_id) in fake_reads.iter() { match fake_read.base { PlaceBase::Upvar(upvar_id) => { if upvar_is_local_variable( - upvars, + self.upvars, upvar_id.var_path.hir_id, body_owner_is_closure, ) { @@ -837,7 +1005,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { ); } }; - self.delegate.fake_read( + self.delegate.borrow_mut().fake_read( &PlaceWithHirId { place: fake_read.clone(), hir_id: *hir_id }, *cause, *hir_id, @@ -845,10 +1013,14 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } } - if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id) + if let Some(min_captures) = + self.cx.typeck_results().closure_min_captures.get(&closure_def_id) { for (var_hir_id, min_list) in min_captures.iter() { - if upvars.map_or(body_owner_is_closure, |upvars| !upvars.contains_key(var_hir_id)) { + if self + .upvars + .map_or(body_owner_is_closure, |upvars| !upvars.contains_key(var_hir_id)) + { // The nested closure might be capturing the current (enclosing) closure's local variables. // We check if the root variable is ever mentioned within the enclosing closure, if not // then for the current body (if it's a closure) these aren't captures, we will ignore them. @@ -860,7 +1032,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { let place_base = if body_owner_is_closure { // Mark the place to be captured by the enclosing closure - PlaceBase::Upvar(ty::UpvarId::new(*var_hir_id, self.body_owner)) + PlaceBase::Upvar(ty::UpvarId::new(*var_hir_id, self.cx.body_owner_def_id())) } else { // If the body owner isn't a closure then the variable must // be a local variable @@ -878,10 +1050,10 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { match capture_info.capture_kind { ty::UpvarCapture::ByValue => { - self.delegate_consume(&place_with_id, place_with_id.hir_id); + self.consume_or_copy(&place_with_id, place_with_id.hir_id); } ty::UpvarCapture::ByRef(upvar_borrow) => { - self.delegate.borrow( + self.delegate.borrow_mut().borrow( &place_with_id, place_with_id.hir_id, upvar_borrow, @@ -891,53 +1063,733 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { } } } + + Ok(()) } } -fn copy_or_move<'a, 'tcx>( - mc: &mc::MemCategorizationContext<'a, 'tcx>, - place_with_id: &PlaceWithHirId<'tcx>, -) -> ConsumeMode { - if !mc.type_is_copy_modulo_regions(place_with_id.place.ty()) { - ConsumeMode::Move - } else { - ConsumeMode::Copy +/// The job of the categorization methods is to analyze an expression to +/// determine what kind of memory is used in evaluating it (for example, +/// where dereferences occur and what kind of pointer is dereferenced; +/// whether the memory is mutable, etc.). +/// +/// Categorization effectively transforms all of our expressions into +/// expressions of the following forms (the actual enum has many more +/// possibilities, naturally, but they are all variants of these base +/// forms): +/// ```ignore (not-rust) +/// E = rvalue // some computed rvalue +/// | x // address of a local variable or argument +/// | *E // deref of a ptr +/// | E.comp // access to an interior component +/// ``` +/// Imagine a routine ToAddr(Expr) that evaluates an expression and returns an +/// address where the result is to be found. If Expr is a place, then this +/// is the address of the place. If `Expr` is an rvalue, this is the address of +/// some temporary spot in memory where the result is stored. +/// +/// Now, `cat_expr()` classifies the expression `Expr` and the address `A = ToAddr(Expr)` +/// as follows: +/// +/// - `cat`: what kind of expression was this? This is a subset of the +/// full expression forms which only includes those that we care about +/// for the purpose of the analysis. +/// - `mutbl`: mutability of the address `A`. +/// - `ty`: the type of data found at the address `A`. +/// +/// The resulting categorization tree differs somewhat from the expressions +/// themselves. For example, auto-derefs are explicit. Also, an index `a[b]` is +/// decomposed into two operations: a dereference to reach the array data and +/// then an index to jump forward to the relevant item. +/// +/// ## By-reference upvars +/// +/// One part of the codegen which may be non-obvious is that we translate +/// closure upvars into the dereference of a borrowed pointer; this more closely +/// resembles the runtime codegen. So, for example, if we had: +/// +/// let mut x = 3; +/// let y = 5; +/// let inc = || x += y; +/// +/// Then when we categorize `x` (*within* the closure) we would yield a +/// result of `*x'`, effectively, where `x'` is a `Categorization::Upvar` reference +/// tied to `x`. The type of `x'` will be a borrowed pointer. +impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> { + fn resolve_type_vars_or_error( + &self, + id: HirId, + ty: Option>, + ) -> Result, Cx::Error> { + match ty { + Some(ty) => { + let ty = self.cx.resolve_vars_if_possible(ty); + self.cx.error_reported_in_ty(ty)?; + if ty.is_ty_var() { + debug!("resolve_type_vars_or_error: infer var from {:?}", ty); + Err(self + .cx + .report_error(self.cx.tcx().hir().span(id), "encountered type variable")) + } else { + Ok(ty) + } + } + None => { + // FIXME: We shouldn't be relying on the infcx being tainted. + self.cx.tainted_by_errors()?; + bug!( + "no type for node {} in mem_categorization", + self.cx.tcx().hir().node_to_string(id) + ); + } + } } -} -// - If a place is used in a `ByValue` context then move it if it's not a `Copy` type. -// - If the place that is a `Copy` type consider it an `ImmBorrow`. -fn delegate_consume<'a, 'tcx>( - mc: &mc::MemCategorizationContext<'a, 'tcx>, - delegate: &mut (dyn Delegate<'tcx> + 'a), - place_with_id: &PlaceWithHirId<'tcx>, - diag_expr_id: HirId, -) { - debug!("delegate_consume(place_with_id={:?})", place_with_id); + fn node_ty(&self, hir_id: HirId) -> Result, Cx::Error> { + self.resolve_type_vars_or_error(hir_id, self.cx.typeck_results().node_type_opt(hir_id)) + } - let mode = copy_or_move(mc, place_with_id); + fn expr_ty(&self, expr: &hir::Expr<'_>) -> Result, Cx::Error> { + self.resolve_type_vars_or_error(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr)) + } - match mode { - ConsumeMode::Move => delegate.consume(place_with_id, diag_expr_id), - ConsumeMode::Copy => delegate.copy(place_with_id, diag_expr_id), + fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Result, Cx::Error> { + self.resolve_type_vars_or_error( + expr.hir_id, + self.cx.typeck_results().expr_ty_adjusted_opt(expr), + ) + } + + /// Returns the type of value that this pattern matches against. + /// Some non-obvious cases: + /// + /// - a `ref x` binding matches against a value of type `T` and gives + /// `x` the type `&T`; we return `T`. + /// - a pattern with implicit derefs (thanks to default binding + /// modes #42640) may look like `Some(x)` but in fact have + /// implicit deref patterns attached (e.g., it is really + /// `&Some(x)`). In that case, we return the "outermost" type + /// (e.g., `&Option`). + fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> Result, Cx::Error> { + // Check for implicit `&` types wrapping the pattern; note + // that these are never attached to binding patterns, so + // actually this is somewhat "disjoint" from the code below + // that aims to account for `ref x`. + if let Some(vec) = self.cx.typeck_results().pat_adjustments().get(pat.hir_id) { + if let Some(first_ty) = vec.first() { + debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty); + return Ok(*first_ty); + } + } + + self.pat_ty_unadjusted(pat) + } + + /// Like `TypeckResults::pat_ty`, but ignores implicit `&` patterns. + fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> Result, Cx::Error> { + let base_ty = self.node_ty(pat.hir_id)?; + trace!(?base_ty); + + // This code detects whether we are looking at a `ref x`, + // and if so, figures out what the type *being borrowed* is. + match pat.kind { + PatKind::Binding(..) => { + let bm = *self + .cx + .typeck_results() + .pat_binding_modes() + .get(pat.hir_id) + .expect("missing binding mode"); + + if matches!(bm.0, hir::ByRef::Yes(_)) { + // a bind-by-ref means that the base_ty will be the type of the ident itself, + // but what we want here is the type of the underlying value being borrowed. + // So peel off one-level, turning the &T into T. + match self + .cx + .try_structurally_resolve_type(pat.span, base_ty) + .builtin_deref(false) + { + Some(ty) => Ok(ty), + None => { + debug!("By-ref binding of non-derefable type"); + Err(self + .cx + .report_error(pat.span, "by-ref binding of non-derefable type")) + } + } + } else { + Ok(base_ty) + } + } + _ => Ok(base_ty), + } + } + + fn cat_expr(&self, expr: &hir::Expr<'_>) -> Result, Cx::Error> { + self.cat_expr_(expr, self.cx.typeck_results().expr_adjustments(expr)) + } + + /// This recursion helper avoids going through *too many* + /// adjustments, since *only* non-overloaded deref recurses. + fn cat_expr_( + &self, + expr: &hir::Expr<'_>, + adjustments: &[adjustment::Adjustment<'tcx>], + ) -> Result, Cx::Error> { + match adjustments.split_last() { + None => self.cat_expr_unadjusted(expr), + Some((adjustment, previous)) => { + self.cat_expr_adjusted_with(expr, || self.cat_expr_(expr, previous), adjustment) + } + } + } + + fn cat_expr_adjusted( + &self, + expr: &hir::Expr<'_>, + previous: PlaceWithHirId<'tcx>, + adjustment: &adjustment::Adjustment<'tcx>, + ) -> Result, Cx::Error> { + self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment) + } + + fn cat_expr_adjusted_with( + &self, + expr: &hir::Expr<'_>, + previous: F, + adjustment: &adjustment::Adjustment<'tcx>, + ) -> Result, Cx::Error> + where + F: FnOnce() -> Result, Cx::Error>, + { + let target = self.cx.resolve_vars_if_possible(adjustment.target); + match adjustment.kind { + adjustment::Adjust::Deref(overloaded) => { + // Equivalent to *expr or something similar. + let base = if let Some(deref) = overloaded { + let ref_ty = Ty::new_ref(self.cx.tcx(), deref.region, target, deref.mutbl); + self.cat_rvalue(expr.hir_id, ref_ty) + } else { + previous()? + }; + self.cat_deref(expr.hir_id, base) + } + + adjustment::Adjust::NeverToAny + | adjustment::Adjust::Pointer(_) + | adjustment::Adjust::Borrow(_) + | adjustment::Adjust::DynStar => { + // Result is an rvalue. + Ok(self.cat_rvalue(expr.hir_id, target)) + } + } } -} -fn is_multivariant_adt(ty: Ty<'_>) -> bool { - if let ty::Adt(def, _) = ty.kind() { - // Note that if a non-exhaustive SingleVariant is defined in another crate, we need - // to assume that more cases will be added to the variant in the future. This mean - // that we should handle non-exhaustive SingleVariant the same way we would handle - // a MultiVariant. - // If the variant is not local it must be defined in another crate. - let is_non_exhaustive = match def.adt_kind() { - AdtKind::Struct | AdtKind::Union => { - def.non_enum_variant().is_field_list_non_exhaustive() - } - AdtKind::Enum => def.is_variant_list_non_exhaustive(), + fn cat_expr_unadjusted(&self, expr: &hir::Expr<'_>) -> Result, Cx::Error> { + let expr_ty = self.expr_ty(expr)?; + match expr.kind { + hir::ExprKind::Unary(hir::UnOp::Deref, e_base) => { + if self.cx.typeck_results().is_method_call(expr) { + self.cat_overloaded_place(expr, e_base) + } else { + let base = self.cat_expr(e_base)?; + self.cat_deref(expr.hir_id, base) + } + } + + hir::ExprKind::Field(base, _) => { + let base = self.cat_expr(base)?; + debug!(?base); + + let field_idx = self + .cx + .typeck_results() + .field_indices() + .get(expr.hir_id) + .cloned() + .expect("Field index not found"); + + Ok(self.cat_projection( + expr.hir_id, + base, + expr_ty, + ProjectionKind::Field(field_idx, FIRST_VARIANT), + )) + } + + hir::ExprKind::Index(base, _, _) => { + if self.cx.typeck_results().is_method_call(expr) { + // If this is an index implemented by a method call, then it + // will include an implicit deref of the result. + // The call to index() returns a `&T` value, which + // is an rvalue. That is what we will be + // dereferencing. + self.cat_overloaded_place(expr, base) + } else { + let base = self.cat_expr(base)?; + Ok(self.cat_projection(expr.hir_id, base, expr_ty, ProjectionKind::Index)) + } + } + + hir::ExprKind::Path(ref qpath) => { + let res = self.cx.typeck_results().qpath_res(qpath, expr.hir_id); + self.cat_res(expr.hir_id, expr.span, expr_ty, res) + } + + hir::ExprKind::Type(e, _) => self.cat_expr(e), + + hir::ExprKind::AddrOf(..) + | hir::ExprKind::Call(..) + | hir::ExprKind::Assign(..) + | hir::ExprKind::AssignOp(..) + | hir::ExprKind::Closure { .. } + | hir::ExprKind::Ret(..) + | hir::ExprKind::Become(..) + | hir::ExprKind::Unary(..) + | hir::ExprKind::Yield(..) + | hir::ExprKind::MethodCall(..) + | hir::ExprKind::Cast(..) + | hir::ExprKind::DropTemps(..) + | hir::ExprKind::Array(..) + | hir::ExprKind::If(..) + | hir::ExprKind::Tup(..) + | hir::ExprKind::Binary(..) + | hir::ExprKind::Block(..) + | hir::ExprKind::Let(..) + | hir::ExprKind::Loop(..) + | hir::ExprKind::Match(..) + | hir::ExprKind::Lit(..) + | hir::ExprKind::ConstBlock(..) + | hir::ExprKind::Break(..) + | hir::ExprKind::Continue(..) + | hir::ExprKind::Struct(..) + | hir::ExprKind::Repeat(..) + | hir::ExprKind::InlineAsm(..) + | hir::ExprKind::OffsetOf(..) + | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr_ty)), + } + } + + fn cat_res( + &self, + hir_id: HirId, + span: Span, + expr_ty: Ty<'tcx>, + res: Res, + ) -> Result, Cx::Error> { + match res { + Res::Def( + DefKind::Ctor(..) + | DefKind::Const + | DefKind::ConstParam + | DefKind::AssocConst + | DefKind::Fn + | DefKind::AssocFn, + _, + ) + | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, expr_ty)), + + Res::Def(DefKind::Static { .. }, _) => { + Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new())) + } + + Res::Local(var_id) => { + if self.upvars.is_some_and(|upvars| upvars.contains_key(&var_id)) { + self.cat_upvar(hir_id, var_id) + } else { + Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Local(var_id), Vec::new())) + } + } + + def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def), + } + } + + /// Categorize an upvar. + /// + /// Note: the actual upvar access contains invisible derefs of closure + /// environment and upvar reference as appropriate. Only regionck cares + /// about these dereferences, so we let it compute them as needed. + fn cat_upvar(&self, hir_id: HirId, var_id: HirId) -> Result, Cx::Error> { + let closure_expr_def_id = self.cx.body_owner_def_id(); + + let upvar_id = ty::UpvarId { + var_path: ty::UpvarPath { hir_id: var_id }, + closure_expr_id: closure_expr_def_id, }; - def.variants().len() > 1 || (!def.did().is_local() && is_non_exhaustive) - } else { - false + let var_ty = self.node_ty(var_id)?; + + Ok(PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new())) + } + + fn cat_rvalue(&self, hir_id: HirId, expr_ty: Ty<'tcx>) -> PlaceWithHirId<'tcx> { + PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new()) + } + + fn cat_projection( + &self, + node: HirId, + base_place: PlaceWithHirId<'tcx>, + ty: Ty<'tcx>, + kind: ProjectionKind, + ) -> PlaceWithHirId<'tcx> { + let place_ty = base_place.place.ty(); + let mut projections = base_place.place.projections; + + let node_ty = self.cx.typeck_results().node_type(node); + // Opaque types can't have field projections, but we can instead convert + // the current place in-place (heh) to the hidden type, and then apply all + // follow up projections on that. + if node_ty != place_ty + && self + .cx + .try_structurally_resolve_type( + self.cx.tcx().hir().span(base_place.hir_id), + place_ty, + ) + .is_impl_trait() + { + projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty }); + } + projections.push(Projection { kind, ty }); + PlaceWithHirId::new(node, base_place.place.base_ty, base_place.place.base, projections) + } + + fn cat_overloaded_place( + &self, + expr: &hir::Expr<'_>, + base: &hir::Expr<'_>, + ) -> Result, Cx::Error> { + // Reconstruct the output assuming it's a reference with the + // same region and mutability as the receiver. This holds for + // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. + let place_ty = self.expr_ty(expr)?; + let base_ty = self.expr_ty_adjusted(base)?; + + let ty::Ref(region, _, mutbl) = + *self.cx.try_structurally_resolve_type(base.span, base_ty).kind() + else { + span_bug!(expr.span, "cat_overloaded_place: base is not a reference"); + }; + let ref_ty = Ty::new_ref(self.cx.tcx(), region, place_ty, mutbl); + + let base = self.cat_rvalue(expr.hir_id, ref_ty); + self.cat_deref(expr.hir_id, base) + } + + fn cat_deref( + &self, + node: HirId, + base_place: PlaceWithHirId<'tcx>, + ) -> Result, Cx::Error> { + let base_curr_ty = base_place.place.ty(); + let deref_ty = match self + .cx + .try_structurally_resolve_type( + self.cx.tcx().hir().span(base_place.hir_id), + base_curr_ty, + ) + .builtin_deref(true) + { + Some(ty) => ty, + None => { + debug!("explicit deref of non-derefable type: {:?}", base_curr_ty); + return Err(self.cx.report_error( + self.cx.tcx().hir().span(node), + "explicit deref of non-derefable type", + )); + } + }; + let mut projections = base_place.place.projections; + projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty }); + + Ok(PlaceWithHirId::new(node, base_place.place.base_ty, base_place.place.base, projections)) + } + + /// Returns the variant index for an ADT used within a Struct or TupleStruct pattern + /// Here `pat_hir_id` is the HirId of the pattern itself. + fn variant_index_for_adt( + &self, + qpath: &hir::QPath<'_>, + pat_hir_id: HirId, + span: Span, + ) -> Result { + let res = self.cx.typeck_results().qpath_res(qpath, pat_hir_id); + let ty = self.cx.typeck_results().node_type(pat_hir_id); + let ty::Adt(adt_def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() else { + return Err(self + .cx + .report_error(span, "struct or tuple struct pattern not applied to an ADT")); + }; + + match res { + Res::Def(DefKind::Variant, variant_id) => Ok(adt_def.variant_index_with_id(variant_id)), + Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => { + Ok(adt_def.variant_index_with_ctor_id(variant_ctor_id)) + } + Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _) + | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) + | Res::SelfCtor(..) + | Res::SelfTyParam { .. } + | Res::SelfTyAlias { .. } => { + // Structs and Unions have only have one variant. + Ok(FIRST_VARIANT) + } + _ => bug!("expected ADT path, found={:?}", res), + } + } + + /// Returns the total number of fields in an ADT variant used within a pattern. + /// Here `pat_hir_id` is the HirId of the pattern itself. + fn total_fields_in_adt_variant( + &self, + pat_hir_id: HirId, + variant_index: VariantIdx, + span: Span, + ) -> Result { + let ty = self.cx.typeck_results().node_type(pat_hir_id); + match self.cx.try_structurally_resolve_type(span, ty).kind() { + ty::Adt(adt_def, _) => Ok(adt_def.variant(variant_index).fields.len()), + _ => { + self.cx + .tcx() + .dcx() + .span_bug(span, "struct or tuple struct pattern not applied to an ADT"); + } + } + } + + /// Returns the total number of fields in a tuple used within a Tuple pattern. + /// Here `pat_hir_id` is the HirId of the pattern itself. + fn total_fields_in_tuple(&self, pat_hir_id: HirId, span: Span) -> Result { + let ty = self.cx.typeck_results().node_type(pat_hir_id); + match self.cx.try_structurally_resolve_type(span, ty).kind() { + ty::Tuple(args) => Ok(args.len()), + _ => Err(self.cx.report_error(span, "tuple pattern not applied to a tuple")), + } + } + + /// Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it + /// is being matched against. + /// + /// In general, the way that this works is that we walk down the pattern, + /// constructing a `PlaceWithHirId` that represents the path that will be taken + /// to reach the value being matched. + fn cat_pattern( + &self, + mut place_with_id: PlaceWithHirId<'tcx>, + pat: &hir::Pat<'_>, + op: &mut F, + ) -> Result<(), Cx::Error> + where + F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>) -> Result<(), Cx::Error>, + { + // If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly. + // `PlaceWithHirId`s are constructed differently from patterns. For example, in + // + // ``` + // match foo { + // &&Some(x, ) => { ... }, + // _ => { ... }, + // } + // ``` + // + // the pattern `&&Some(x,)` is represented as `Ref { Ref { TupleStruct }}`. To build the + // corresponding `PlaceWithHirId` we start with the `PlaceWithHirId` for `foo`, and then, by traversing the + // pattern, try to answer the question: given the address of `foo`, how is `x` reached? + // + // `&&Some(x,)` `place_foo` + // `&Some(x,)` `deref { place_foo}` + // `Some(x,)` `deref { deref { place_foo }}` + // `(x,)` `field0 { deref { deref { place_foo }}}` <- resulting place + // + // The above example has no adjustments. If the code were instead the (after adjustments, + // equivalent) version + // + // ``` + // match foo { + // Some(x, ) => { ... }, + // _ => { ... }, + // } + // ``` + // + // Then we see that to get the same result, we must start with + // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)` + // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`. + for _ in + 0..self.cx.typeck_results().pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len()) + { + debug!("applying adjustment to place_with_id={:?}", place_with_id); + place_with_id = self.cat_deref(pat.hir_id, place_with_id)?; + } + let place_with_id = place_with_id; // lose mutability + debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id); + + // Invoke the callback, but only now, after the `place_with_id` has adjusted. + // + // To see that this makes sense, consider `match &Some(3) { Some(x) => { ... }}`. In that + // case, the initial `place_with_id` will be that for `&Some(3)` and the pattern is `Some(x)`. We + // don't want to call `op` with these incompatible values. As written, what happens instead + // is that `op` is called with the adjusted place (that for `*&Some(3)`) and the pattern + // `Some(x)` (which matches). Recursing once more, `*&Some(3)` and the pattern `Some(x)` + // result in the place `Downcast(*&Some(3)).0` associated to `x` and invoke `op` with + // that (where the `ref` on `x` is implied). + op(&place_with_id, pat)?; + + match pat.kind { + PatKind::Tuple(subpats, dots_pos) => { + // (p1, ..., pN) + let total_fields = self.total_fields_in_tuple(pat.hir_id, pat.span)?; + + for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) { + let subpat_ty = self.pat_ty_adjusted(subpat)?; + let projection_kind = + ProjectionKind::Field(FieldIdx::from_usize(i), FIRST_VARIANT); + let sub_place = self.cat_projection( + pat.hir_id, + place_with_id.clone(), + subpat_ty, + projection_kind, + ); + self.cat_pattern(sub_place, subpat, op)?; + } + } + + PatKind::TupleStruct(ref qpath, subpats, dots_pos) => { + // S(p1, ..., pN) + let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?; + let total_fields = + self.total_fields_in_adt_variant(pat.hir_id, variant_index, pat.span)?; + + for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) { + let subpat_ty = self.pat_ty_adjusted(subpat)?; + let projection_kind = + ProjectionKind::Field(FieldIdx::from_usize(i), variant_index); + let sub_place = self.cat_projection( + pat.hir_id, + place_with_id.clone(), + subpat_ty, + projection_kind, + ); + self.cat_pattern(sub_place, subpat, op)?; + } + } + + PatKind::Struct(ref qpath, field_pats, _) => { + // S { f1: p1, ..., fN: pN } + + let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?; + + for fp in field_pats { + let field_ty = self.pat_ty_adjusted(fp.pat)?; + let field_index = self + .cx + .typeck_results() + .field_indices() + .get(fp.hir_id) + .cloned() + .expect("no index for a field"); + + let field_place = self.cat_projection( + pat.hir_id, + place_with_id.clone(), + field_ty, + ProjectionKind::Field(field_index, variant_index), + ); + self.cat_pattern(field_place, fp.pat, op)?; + } + } + + PatKind::Or(pats) => { + for pat in pats { + self.cat_pattern(place_with_id.clone(), pat, op)?; + } + } + + PatKind::Binding(.., Some(subpat)) => { + self.cat_pattern(place_with_id, subpat, op)?; + } + + PatKind::Box(subpat) | PatKind::Ref(subpat, _) => { + // box p1, &p1, &mut p1. we can ignore the mutability of + // PatKind::Ref since that information is already contained + // in the type. + let subplace = self.cat_deref(pat.hir_id, place_with_id)?; + self.cat_pattern(subplace, subpat, op)?; + } + PatKind::Deref(subpat) => { + let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpat); + let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; + let re_erased = self.cx.tcx().lifetimes.re_erased; + let ty = self.pat_ty_adjusted(subpat)?; + let ty = Ty::new_ref(self.cx.tcx(), re_erased, ty, mutability); + // A deref pattern generates a temporary. + let place = self.cat_rvalue(pat.hir_id, ty); + self.cat_pattern(place, subpat, op)?; + } + + PatKind::Slice(before, ref slice, after) => { + let Some(element_ty) = place_with_id.place.ty().builtin_index() else { + debug!("explicit index of non-indexable type {:?}", place_with_id); + return Err(self + .cx + .report_error(pat.span, "explicit index of non-indexable type")); + }; + let elt_place = self.cat_projection( + pat.hir_id, + place_with_id.clone(), + element_ty, + ProjectionKind::Index, + ); + for before_pat in before { + self.cat_pattern(elt_place.clone(), before_pat, op)?; + } + if let Some(slice_pat) = *slice { + let slice_pat_ty = self.pat_ty_adjusted(slice_pat)?; + let slice_place = self.cat_projection( + pat.hir_id, + place_with_id, + slice_pat_ty, + ProjectionKind::Subslice, + ); + self.cat_pattern(slice_place, slice_pat, op)?; + } + for after_pat in after { + self.cat_pattern(elt_place.clone(), after_pat, op)?; + } + } + + PatKind::Path(_) + | PatKind::Binding(.., None) + | PatKind::Lit(..) + | PatKind::Range(..) + | PatKind::Never + | PatKind::Wild + | PatKind::Err(_) => { + // always ok + } + } + + Ok(()) + } + + fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool { + if let ty::Adt(def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() { + // Note that if a non-exhaustive SingleVariant is defined in another crate, we need + // to assume that more cases will be added to the variant in the future. This mean + // that we should handle non-exhaustive SingleVariant the same way we would handle + // a MultiVariant. + // If the variant is not local it must be defined in another crate. + let is_non_exhaustive = match def.adt_kind() { + AdtKind::Struct | AdtKind::Union => { + def.non_enum_variant().is_field_list_non_exhaustive() + } + AdtKind::Enum => def.is_variant_list_non_exhaustive(), + }; + def.variants().len() > 1 || (!def.did().is_local() && is_non_exhaustive) + } else { + false + } } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 552747bdc5272..b32cab6d3f71f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -409,7 +409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> LoweredTy<'tcx> { let ty = self.lowerer().lower_ty(hir_ty); - self.register_wf_obligation(ty.into(), hir_ty.span, traits::WellFormed(None)); + self.register_wf_obligation(ty.into(), hir_ty.span, ObligationCauseCode::WellFormed(None)); LoweredTy::from_raw(self, hir_ty.span, ty) } @@ -520,7 +520,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for arg in args.iter().filter(|arg| { matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) }) { - self.register_wf_obligation(arg, expr.span, traits::WellFormed(None)); + self.register_wf_obligation(arg, expr.span, ObligationCauseCode::WellFormed(None)); } } @@ -624,10 +624,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// returns a type of `&T`, but the actual type we assign to the /// *expression* is `T`. So this function just peels off the return /// type by one layer to yield `T`. - pub(crate) fn make_overloaded_place_return_type( - &self, - method: MethodCallee<'tcx>, - ) -> ty::TypeAndMut<'tcx> { + pub(crate) fn make_overloaded_place_return_type(&self, method: MethodCallee<'tcx>) -> Ty<'tcx> { // extract method return type, which will be &T; let ret_ty = method.sig.output(); @@ -775,7 +772,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id) { - self.register_wf_obligation(ty.raw.into(), qself.span, traits::WellFormed(None)); + self.register_wf_obligation( + ty.raw.into(), + qself.span, + ObligationCauseCode::WellFormed(None), + ); // Return directly on cache hit. This is useful to avoid doubly reporting // errors with default match binding modes. See #44614. let def = cached_result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)); @@ -814,7 +815,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_wf_obligation( ty.raw.into(), qself.span, - traits::WellFormed(None), + ObligationCauseCode::WellFormed(None), ); } @@ -848,7 +849,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); if result.is_ok() { - self.register_wf_obligation(ty.raw.into(), qself.span, traits::WellFormed(None)); + self.register_wf_obligation( + ty.raw.into(), + qself.span, + ObligationCauseCode::WellFormed(None), + ); } // Write back the new resolution. @@ -1404,11 +1409,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir_id: HirId, ) { self.add_required_obligations_with_code(span, def_id, args, |idx, span| { - if span.is_dummy() { - ObligationCauseCode::ExprItemObligation(def_id, hir_id, idx) - } else { - ObligationCauseCode::ExprBindingObligation(def_id, span, hir_id, idx) - } + ObligationCauseCode::WhereClauseInExpr(def_id, span, hir_id, idx) }) } 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 a718760f4d895..c3525f175da8e 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 @@ -14,8 +14,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, error: &mut traits::FulfillmentError<'tcx>, ) -> bool { - let (traits::ExprItemObligation(def_id, hir_id, idx) - | traits::ExprBindingObligation(def_id, _, hir_id, idx)) = + let ObligationCauseCode::WhereClauseInExpr(def_id, _, hir_id, idx) = *error.obligation.cause.code().peel_derives() else { return false; @@ -167,7 +166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // the method's turbofish segments but still use `FunctionArgumentObligation` // elsewhere. Hopefully this doesn't break something. error.obligation.cause.map_code(|parent_code| { - ObligationCauseCode::FunctionArgumentObligation { + ObligationCauseCode::FunctionArg { arg_hir_id: receiver.hir_id, call_hir_id: hir_id, parent_code, @@ -360,12 +359,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error: &traits::FulfillmentError<'tcx>, span: Span, ) -> bool { - if let traits::FulfillmentErrorCode::SelectionError( - traits::SelectionError::SignatureMismatch(box traits::SignatureMismatchData { - expected_trait_ref, - .. - }), - ) = error.code + if let traits::FulfillmentErrorCode::Select(traits::SelectionError::SignatureMismatch( + box traits::SignatureMismatchData { expected_trait_ref, .. }, + )) = error.code && let ty::Closure(def_id, _) | ty::Coroutine(def_id, ..) = expected_trait_ref.self_ty().kind() && span.overlaps(self.tcx.def_span(*def_id)) @@ -459,12 +455,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.blame_specific_expr_if_possible(error, arg_expr) } - error.obligation.cause.map_code(|parent_code| { - ObligationCauseCode::FunctionArgumentObligation { - arg_hir_id: arg.hir_id, - call_hir_id, - parent_code, - } + error.obligation.cause.map_code(|parent_code| ObligationCauseCode::FunctionArg { + arg_hir_id: arg.hir_id, + call_hir_id, + parent_code, }); return true; } else if args_referencing_param.len() > 0 { @@ -517,12 +511,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> { match obligation_cause_code { - traits::ObligationCauseCode::ExprBindingObligation(_, _, _, _) => { + traits::ObligationCauseCode::WhereClauseInExpr(_, _, _, _) => { // This is the "root"; we assume that the `expr` is already pointing here. // Therefore, we return `Ok` so that this `expr` can be refined further. Ok(expr) } - traits::ObligationCauseCode::ImplDerivedObligation(impl_derived) => self + traits::ObligationCauseCode::ImplDerived(impl_derived) => self .blame_specific_expr_if_possible_for_derived_predicate_obligation( impl_derived, expr, @@ -560,7 +554,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// only a partial success - but it cannot be refined even further. fn blame_specific_expr_if_possible_for_derived_predicate_obligation( &self, - obligation: &traits::ImplDerivedObligationCause<'tcx>, + obligation: &traits::ImplDerivedCause<'tcx>, expr: &'tcx hir::Expr<'tcx>, ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> { // First, we attempt to refine the `expr` for our span using the parent obligation. @@ -729,7 +723,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did()); - if drill_generic_index >= struct_generic_parameters.params.len() { + if drill_generic_index >= struct_generic_parameters.own_params.len() { return Err(expr); } @@ -852,7 +846,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did()); - if drill_generic_index >= struct_generic_parameters.params.len() { + if drill_generic_index >= struct_generic_parameters.own_params.len() { return Err(expr); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index e45e0884affb1..5fa715dc7618b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -31,16 +31,14 @@ use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_hir_analysis::structured_errors::StructuredDiag; use rustc_index::IndexVec; use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt}; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::TypeTrace; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; -use rustc_middle::traits::ObligationCauseCode::ExprBindingObligation; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt}; use rustc_session::Session; use rustc_span::symbol::{kw, Ident}; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{sym, BytePos, Span, DUMMY_SP}; use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; use std::iter; @@ -204,7 +202,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // All the input types from the fn signature must outlive the call // so as to validate implied bounds. for (&fn_input_ty, arg_expr) in iter::zip(formal_input_tys, provided_args) { - self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation); + self.register_wf_obligation( + fn_input_ty.into(), + arg_expr.span, + ObligationCauseCode::Misc, + ); } let mut err_code = E0061; @@ -2011,7 +2013,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for (span, code) in errors_causecode { self.dcx().try_steal_modify_and_emit_err(span, StashKey::MaybeForgetReturn, |err| { if let Some(fn_sig) = self.body_fn_sig() - && let ExprBindingObligation(_, _, binding_hir_id, ..) = code + && let ObligationCauseCode::WhereClauseInExpr(_, _, binding_hir_id, ..) = code && !fn_sig.output().is_unit() { let mut block_num = 0; @@ -2100,7 +2102,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // This is because due to normalization, we often register duplicate // obligations with misc obligations that are basically impossible to - // line back up with a useful ExprBindingObligation. + // line back up with a useful WhereClauseInExpr. for error in not_adjusted { for (span, predicate, cause) in &remap_cause { if *predicate == error.obligation.predicate @@ -2180,13 +2182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let trait_ref = ty::TraitRef::new( self.tcx, self.tcx.fn_trait_kind_to_def_id(call_kind)?, - [ - callee_ty, - self.next_ty_var(TypeVariableOrigin { - param_def_id: None, - span: rustc_span::DUMMY_SP, - }), - ], + [callee_ty, self.next_ty_var(DUMMY_SP)], ); let obligation = traits::Obligation::new( self.tcx, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index c2068d9f66b8f..2ef254f644f73 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -1,9 +1,8 @@ //! A utility module to inspect currently ambiguous obligations in the current context. -use crate::rustc_middle::ty::TypeVisitableExt; use crate::FnCtxt; use rustc_infer::traits::solve::Goal; use rustc_infer::traits::{self, ObligationCause}; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_span::Span; use rustc_trait_selection::solve::inspect::ProofTreeInferCtxtExt; use rustc_trait_selection::solve::inspect::{InspectConfig, InspectGoal, ProofTreeVisitor}; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 794b854ca5f95..afba812a8e7bb 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -19,8 +19,6 @@ use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_infer::infer; use rustc_infer::infer::error_reporting::sub_relations::SubRelations; use rustc_infer::infer::error_reporting::TypeErrCtxt; -use rustc_infer::infer::type_variable::TypeVariableOrigin; -use rustc_middle::infer::unify_key::ConstVariableOrigin; use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::Session; use rustc_span::symbol::Ident; @@ -156,7 +154,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn misc(&self, span: Span) -> ObligationCause<'tcx> { - self.cause(span, ObligationCauseCode::MiscObligation) + self.cause(span, ObligationCauseCode::Misc) } pub fn sess(&self) -> &Session { @@ -239,7 +237,7 @@ impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> { fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { match param { Some(param) => self.var_for_def(span, param).as_type().unwrap(), - None => self.next_ty_var(TypeVariableOrigin { param_def_id: None, span }), + None => self.next_ty_var(span), } } @@ -258,7 +256,7 @@ impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> { }, ) => self.var_for_effect(param).as_const().unwrap(), Some(param) => self.var_for_def(span, param).as_const().unwrap(), - None => self.next_const_var(ty, ConstVariableOrigin { span, param_def_id: None }), + None => self.next_const_var(ty, span), } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index d00fea4fae498..f1b719f24c7ac 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -6,7 +6,6 @@ use crate::fn_ctxt::rustc_span::BytePos; use crate::hir::is_range_literal; use crate::method::probe; 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; @@ -28,7 +27,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::middle::stability::EvalResult; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ - self, suggest_constraining_type_params, Binder, IsSuggestable, ToPredicate, Ty, + self, suggest_constraining_type_params, Article, Binder, IsSuggestable, ToPredicate, Ty, TypeVisitableExt, }; use rustc_session::errors::ExprParenthesesNeeded; @@ -1701,7 +1700,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } for error in errors { - if let traits::FulfillmentErrorCode::SelectionError( + if let traits::FulfillmentErrorCode::Select( traits::SelectionError::Unimplemented, ) = error.code && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = @@ -2227,7 +2226,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> bool { let tcx = self.tcx; let (adt, args, unwrap) = match expected.kind() { - // In case Option is wanted, but * is provided, suggest calling new + // In case `Option>` is wanted, but `T` is provided, suggest calling `new`. ty::Adt(adt, args) if tcx.is_diagnostic_item(sym::Option, adt.did()) => { let nonzero_type = args.type_at(0); // Unwrap option type. let ty::Adt(adt, args) = nonzero_type.kind() else { @@ -2235,7 +2234,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; (adt, args, "") } - // In case `NonZero<*>` is wanted but `*` is provided, also add `.unwrap()` to satisfy types. + // In case `NonZero` is wanted but `T` is provided, also add `.unwrap()` to satisfy types. ty::Adt(adt, args) => (adt, args, ".unwrap()"), _ => return false, }; @@ -2244,32 +2243,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } - // FIXME: This can be simplified once `NonZero` is stable. - let coercable_types = [ - ("NonZeroU8", tcx.types.u8), - ("NonZeroU16", tcx.types.u16), - ("NonZeroU32", tcx.types.u32), - ("NonZeroU64", tcx.types.u64), - ("NonZeroU128", tcx.types.u128), - ("NonZeroI8", tcx.types.i8), - ("NonZeroI16", tcx.types.i16), - ("NonZeroI32", tcx.types.i32), - ("NonZeroI64", tcx.types.i64), - ("NonZeroI128", tcx.types.i128), - ]; - let int_type = args.type_at(0); - - let Some(nonzero_alias) = coercable_types.iter().find_map(|(nonzero_alias, t)| { - if *t == int_type && self.can_coerce(expr_ty, *t) { Some(nonzero_alias) } else { None } - }) else { + if !self.can_coerce(expr_ty, int_type) { return false; - }; + } err.multipart_suggestion( - format!("consider calling `{nonzero_alias}::new`"), + format!("consider calling `{}::new`", sym::NonZero), vec![ - (expr.span.shrink_to_lo(), format!("{nonzero_alias}::new(")), + (expr.span.shrink_to_lo(), format!("{}::new(", sym::NonZero)), (expr.span.shrink_to_hi(), format!("){unwrap}")), ], Applicability::MaybeIncorrect, diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index fe0a46924de46..13e4b625e2d0d 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -2,12 +2,11 @@ use crate::FnCtxt; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{HirId, PatKind}; -use rustc_infer::infer::type_variable::TypeVariableOrigin; +use rustc_infer::traits::ObligationCauseCode; use rustc_middle::ty::Ty; use rustc_middle::ty::UserType; use rustc_span::def_id::LocalDefId; use rustc_span::Span; -use rustc_trait_selection::traits; /// Provides context for checking patterns in declarations. More specifically this /// allows us to infer array types if the pattern is irrefutable and allows us to infer @@ -50,7 +49,7 @@ impl<'a> From<&'a hir::LetStmt<'a>> for Declaration<'a> { impl<'a> From<(&'a hir::LetExpr<'a>, HirId)> for Declaration<'a> { fn from((let_expr, hir_id): (&'a hir::LetExpr<'a>, HirId)) -> Self { - let hir::LetExpr { pat, ty, span, init, is_recovered: _ } = *let_expr; + let hir::LetExpr { pat, ty, span, init, recovered: _ } = *let_expr; Declaration { hir_id, pat, ty, span, init: Some(init), origin: DeclOrigin::LetExpr } } } @@ -72,7 +71,7 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { match ty_opt { None => { // Infer the variable's type. - let var_ty = self.fcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span }); + let var_ty = self.fcx.next_ty_var(span); self.fcx.locals.borrow_mut().insert(nid, var_ty); var_ty } @@ -147,7 +146,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { p.span, // ty_span == ident.span iff this is a closure parameter with no type // ascription, or if it's an implicit `self` parameter - traits::SizedArgumentType( + ObligationCauseCode::SizedArgumentType( if ty_span == ident.span && self.fcx.tcx.is_closure_like(self.fcx.body_id.into()) { @@ -160,7 +159,11 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { } } else { if !self.fcx.tcx.features().unsized_locals { - self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id)); + self.fcx.require_type_is_sized( + var_ty, + p.span, + ObligationCauseCode::VariableType(p.hir_id), + ); } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 8bc070bcd36cd..296560dd5baba 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -32,7 +32,6 @@ mod fallback; mod fn_ctxt; mod gather_locals; mod intrinsicck; -mod mem_categorization; mod method; mod op; mod pat; @@ -60,10 +59,8 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::{HirId, HirIdMap, Node}; use rustc_hir_analysis::check::check_abi; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc}; use rustc_middle::query::Providers; -use rustc_middle::traits; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::config; use rustc_span::def_id::LocalDefId; @@ -171,7 +168,7 @@ fn typeck_with_fallback<'tcx>( let wf_code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(def_id))); fcx.register_wf_obligation(expected_type.into(), body.value.span, wf_code); - fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); + fcx.require_type_is_sized(expected_type, body.value.span, ObligationCauseCode::ConstSized); // Gather locals in statics (because of block expressions). GatherLocalsVisitor::new(&fcx).visit_body(body); @@ -246,7 +243,7 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti tcx.impl_trait_ref(item.container_id(tcx)).unwrap().instantiate_identity().args; Some(tcx.type_of(trait_item).instantiate(tcx, args)) } else { - Some(fcx.next_ty_var(TypeVariableOrigin { span, param_def_id: None })) + Some(fcx.next_ty_var(span)) } } else if let Node::AnonConst(_) = node { let id = tcx.local_def_id_to_hir_id(def_id); @@ -254,7 +251,7 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti Node::Ty(&hir::Ty { kind: hir::TyKind::Typeof(ref anon_const), span, .. }) if anon_const.hir_id == id => { - Some(fcx.next_ty_var(TypeVariableOrigin { span, param_def_id: None })) + Some(fcx.next_ty_var(span)) } Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), span, .. }) | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), span, .. }) => { @@ -264,7 +261,7 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti Some(fcx.next_int_var()) } hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == id => { - Some(fcx.next_ty_var(TypeVariableOrigin { span, param_def_id: None })) + Some(fcx.next_ty_var(span)) } _ => None, }) diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs deleted file mode 100644 index b44c2345933fb..0000000000000 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ /dev/null @@ -1,774 +0,0 @@ -//! # Categorization -//! -//! The job of the categorization module is to analyze an expression to -//! determine what kind of memory is used in evaluating it (for example, -//! where dereferences occur and what kind of pointer is dereferenced; -//! whether the memory is mutable, etc.). -//! -//! Categorization effectively transforms all of our expressions into -//! expressions of the following forms (the actual enum has many more -//! possibilities, naturally, but they are all variants of these base -//! forms): -//! ```ignore (not-rust) -//! E = rvalue // some computed rvalue -//! | x // address of a local variable or argument -//! | *E // deref of a ptr -//! | E.comp // access to an interior component -//! ``` -//! Imagine a routine ToAddr(Expr) that evaluates an expression and returns an -//! address where the result is to be found. If Expr is a place, then this -//! is the address of the place. If `Expr` is an rvalue, this is the address of -//! some temporary spot in memory where the result is stored. -//! -//! Now, `cat_expr()` classifies the expression `Expr` and the address `A = ToAddr(Expr)` -//! as follows: -//! -//! - `cat`: what kind of expression was this? This is a subset of the -//! full expression forms which only includes those that we care about -//! for the purpose of the analysis. -//! - `mutbl`: mutability of the address `A`. -//! - `ty`: the type of data found at the address `A`. -//! -//! The resulting categorization tree differs somewhat from the expressions -//! themselves. For example, auto-derefs are explicit. Also, an index `a[b]` is -//! decomposed into two operations: a dereference to reach the array data and -//! then an index to jump forward to the relevant item. -//! -//! ## By-reference upvars -//! -//! One part of the codegen which may be non-obvious is that we translate -//! closure upvars into the dereference of a borrowed pointer; this more closely -//! resembles the runtime codegen. So, for example, if we had: -//! -//! let mut x = 3; -//! let y = 5; -//! let inc = || x += y; -//! -//! Then when we categorize `x` (*within* the closure) we would yield a -//! result of `*x'`, effectively, where `x'` is a `Categorization::Upvar` reference -//! tied to `x`. The type of `x'` will be a borrowed pointer. - -use rustc_middle::hir::place::*; -use rustc_middle::ty::adjustment; -use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; - -use rustc_data_structures::fx::FxIndexMap; -use rustc_hir as hir; -use rustc_hir::def::{CtorOf, DefKind, Res}; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::pat_util::EnumerateAndAdjustIterator; -use rustc_hir::{HirId, PatKind}; -use rustc_infer::infer::InferCtxt; -use rustc_span::Span; -use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; -use rustc_trait_selection::infer::InferCtxtExt; - -pub(crate) trait HirNode { - fn hir_id(&self) -> HirId; -} - -impl HirNode for hir::Expr<'_> { - fn hir_id(&self) -> HirId { - self.hir_id - } -} - -impl HirNode for hir::Pat<'_> { - fn hir_id(&self) -> HirId { - self.hir_id - } -} - -#[derive(Clone)] -pub(crate) struct MemCategorizationContext<'a, 'tcx> { - pub(crate) typeck_results: &'a ty::TypeckResults<'tcx>, - infcx: &'a InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_owner: LocalDefId, - upvars: Option<&'tcx FxIndexMap>, -} - -pub(crate) type McResult = Result; - -impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { - /// Creates a `MemCategorizationContext`. - pub(crate) fn new( - infcx: &'a InferCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_owner: LocalDefId, - typeck_results: &'a ty::TypeckResults<'tcx>, - ) -> MemCategorizationContext<'a, 'tcx> { - MemCategorizationContext { - typeck_results, - infcx, - param_env, - body_owner, - upvars: infcx.tcx.upvars_mentioned(body_owner), - } - } - - pub(crate) fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool { - self.infcx.type_is_copy_modulo_regions(self.param_env, ty) - } - - fn resolve_vars_if_possible(&self, value: T) -> T - where - T: TypeFoldable>, - { - self.infcx.resolve_vars_if_possible(value) - } - - fn is_tainted_by_errors(&self) -> bool { - self.infcx.tainted_by_errors().is_some() - } - - fn resolve_type_vars_or_error(&self, id: HirId, ty: Option>) -> McResult> { - match ty { - Some(ty) => { - let ty = self.resolve_vars_if_possible(ty); - if ty.references_error() || ty.is_ty_var() { - debug!("resolve_type_vars_or_error: error from {:?}", ty); - Err(()) - } else { - Ok(ty) - } - } - // FIXME - None if self.is_tainted_by_errors() => Err(()), - None => { - bug!( - "no type for node {} in mem_categorization", - self.tcx().hir().node_to_string(id) - ); - } - } - } - - pub(crate) fn node_ty(&self, hir_id: HirId) -> McResult> { - self.resolve_type_vars_or_error(hir_id, self.typeck_results.node_type_opt(hir_id)) - } - - fn expr_ty(&self, expr: &hir::Expr<'_>) -> McResult> { - self.resolve_type_vars_or_error(expr.hir_id, self.typeck_results.expr_ty_opt(expr)) - } - - pub(crate) fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> McResult> { - self.resolve_type_vars_or_error(expr.hir_id, self.typeck_results.expr_ty_adjusted_opt(expr)) - } - - /// Returns the type of value that this pattern matches against. - /// Some non-obvious cases: - /// - /// - a `ref x` binding matches against a value of type `T` and gives - /// `x` the type `&T`; we return `T`. - /// - a pattern with implicit derefs (thanks to default binding - /// modes #42640) may look like `Some(x)` but in fact have - /// implicit deref patterns attached (e.g., it is really - /// `&Some(x)`). In that case, we return the "outermost" type - /// (e.g., `&Option`). - pub(crate) fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> McResult> { - // Check for implicit `&` types wrapping the pattern; note - // that these are never attached to binding patterns, so - // actually this is somewhat "disjoint" from the code below - // that aims to account for `ref x`. - if let Some(vec) = self.typeck_results.pat_adjustments().get(pat.hir_id) { - if let Some(first_ty) = vec.first() { - debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty); - return Ok(*first_ty); - } - } - - self.pat_ty_unadjusted(pat) - } - - /// Like `pat_ty`, but ignores implicit `&` patterns. - #[instrument(level = "debug", skip(self), ret)] - fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> McResult> { - let base_ty = self.node_ty(pat.hir_id)?; - trace!(?base_ty); - - // This code detects whether we are looking at a `ref x`, - // and if so, figures out what the type *being borrowed* is. - match pat.kind { - PatKind::Binding(..) => { - let bm = *self - .typeck_results - .pat_binding_modes() - .get(pat.hir_id) - .expect("missing binding mode"); - - if matches!(bm.0, hir::ByRef::Yes(_)) { - // a bind-by-ref means that the base_ty will be the type of the ident itself, - // but what we want here is the type of the underlying value being borrowed. - // So peel off one-level, turning the &T into T. - match base_ty.builtin_deref(false) { - Some(t) => Ok(t.ty), - None => { - debug!("By-ref binding of non-derefable type"); - Err(()) - } - } - } else { - Ok(base_ty) - } - } - _ => Ok(base_ty), - } - } - - pub(crate) fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult> { - // This recursion helper avoids going through *too many* - // adjustments, since *only* non-overloaded deref recurses. - fn helper<'a, 'tcx>( - mc: &MemCategorizationContext<'a, 'tcx>, - expr: &hir::Expr<'_>, - adjustments: &[adjustment::Adjustment<'tcx>], - ) -> McResult> { - match adjustments.split_last() { - None => mc.cat_expr_unadjusted(expr), - Some((adjustment, previous)) => { - mc.cat_expr_adjusted_with(expr, || helper(mc, expr, previous), adjustment) - } - } - } - - helper(self, expr, self.typeck_results.expr_adjustments(expr)) - } - - pub(crate) fn cat_expr_adjusted( - &self, - expr: &hir::Expr<'_>, - previous: PlaceWithHirId<'tcx>, - adjustment: &adjustment::Adjustment<'tcx>, - ) -> McResult> { - self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment) - } - - #[instrument(level = "debug", skip(self, previous))] - fn cat_expr_adjusted_with( - &self, - expr: &hir::Expr<'_>, - previous: F, - adjustment: &adjustment::Adjustment<'tcx>, - ) -> McResult> - where - F: FnOnce() -> McResult>, - { - let target = self.resolve_vars_if_possible(adjustment.target); - match adjustment.kind { - adjustment::Adjust::Deref(overloaded) => { - // Equivalent to *expr or something similar. - let base = if let Some(deref) = overloaded { - let ref_ty = Ty::new_ref(self.tcx(), deref.region, target, deref.mutbl); - self.cat_rvalue(expr.hir_id, ref_ty) - } else { - previous()? - }; - self.cat_deref(expr, base) - } - - adjustment::Adjust::NeverToAny - | adjustment::Adjust::Pointer(_) - | adjustment::Adjust::Borrow(_) - | adjustment::Adjust::DynStar => { - // Result is an rvalue. - Ok(self.cat_rvalue(expr.hir_id, target)) - } - } - } - - #[instrument(level = "debug", skip(self), ret)] - pub(crate) fn cat_expr_unadjusted( - &self, - expr: &hir::Expr<'_>, - ) -> McResult> { - let expr_ty = self.expr_ty(expr)?; - match expr.kind { - hir::ExprKind::Unary(hir::UnOp::Deref, e_base) => { - if self.typeck_results.is_method_call(expr) { - self.cat_overloaded_place(expr, e_base) - } else { - let base = self.cat_expr(e_base)?; - self.cat_deref(expr, base) - } - } - - hir::ExprKind::Field(base, _) => { - let base = self.cat_expr(base)?; - debug!(?base); - - let field_idx = self - .typeck_results - .field_indices() - .get(expr.hir_id) - .cloned() - .expect("Field index not found"); - - Ok(self.cat_projection( - expr, - base, - expr_ty, - ProjectionKind::Field(field_idx, FIRST_VARIANT), - )) - } - - hir::ExprKind::Index(base, _, _) => { - if self.typeck_results.is_method_call(expr) { - // If this is an index implemented by a method call, then it - // will include an implicit deref of the result. - // The call to index() returns a `&T` value, which - // is an rvalue. That is what we will be - // dereferencing. - self.cat_overloaded_place(expr, base) - } else { - let base = self.cat_expr(base)?; - Ok(self.cat_projection(expr, base, expr_ty, ProjectionKind::Index)) - } - } - - hir::ExprKind::Path(ref qpath) => { - let res = self.typeck_results.qpath_res(qpath, expr.hir_id); - self.cat_res(expr.hir_id, expr.span, expr_ty, res) - } - - hir::ExprKind::Type(e, _) => self.cat_expr(e), - - hir::ExprKind::AddrOf(..) - | hir::ExprKind::Call(..) - | hir::ExprKind::Assign(..) - | hir::ExprKind::AssignOp(..) - | hir::ExprKind::Closure { .. } - | hir::ExprKind::Ret(..) - | hir::ExprKind::Become(..) - | hir::ExprKind::Unary(..) - | hir::ExprKind::Yield(..) - | hir::ExprKind::MethodCall(..) - | hir::ExprKind::Cast(..) - | hir::ExprKind::DropTemps(..) - | hir::ExprKind::Array(..) - | hir::ExprKind::If(..) - | hir::ExprKind::Tup(..) - | hir::ExprKind::Binary(..) - | hir::ExprKind::Block(..) - | hir::ExprKind::Let(..) - | hir::ExprKind::Loop(..) - | hir::ExprKind::Match(..) - | hir::ExprKind::Lit(..) - | hir::ExprKind::ConstBlock(..) - | hir::ExprKind::Break(..) - | hir::ExprKind::Continue(..) - | hir::ExprKind::Struct(..) - | hir::ExprKind::Repeat(..) - | hir::ExprKind::InlineAsm(..) - | hir::ExprKind::OffsetOf(..) - | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr_ty)), - } - } - - #[instrument(level = "debug", skip(self, span), ret)] - pub(crate) fn cat_res( - &self, - hir_id: HirId, - span: Span, - expr_ty: Ty<'tcx>, - res: Res, - ) -> McResult> { - match res { - Res::Def( - DefKind::Ctor(..) - | DefKind::Const - | DefKind::ConstParam - | DefKind::AssocConst - | DefKind::Fn - | DefKind::AssocFn, - _, - ) - | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, expr_ty)), - - Res::Def(DefKind::Static { .. }, _) => { - Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new())) - } - - Res::Local(var_id) => { - if self.upvars.is_some_and(|upvars| upvars.contains_key(&var_id)) { - self.cat_upvar(hir_id, var_id) - } else { - Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Local(var_id), Vec::new())) - } - } - - def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def), - } - } - - /// Categorize an upvar. - /// - /// Note: the actual upvar access contains invisible derefs of closure - /// environment and upvar reference as appropriate. Only regionck cares - /// about these dereferences, so we let it compute them as needed. - #[instrument(level = "debug", skip(self), ret)] - fn cat_upvar(&self, hir_id: HirId, var_id: HirId) -> McResult> { - let closure_expr_def_id = self.body_owner; - - let upvar_id = ty::UpvarId { - var_path: ty::UpvarPath { hir_id: var_id }, - closure_expr_id: closure_expr_def_id, - }; - let var_ty = self.node_ty(var_id)?; - - Ok(PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new())) - } - - #[instrument(level = "debug", skip(self), ret)] - pub(crate) fn cat_rvalue(&self, hir_id: HirId, expr_ty: Ty<'tcx>) -> PlaceWithHirId<'tcx> { - PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new()) - } - - #[instrument(level = "debug", skip(self, node), ret)] - pub(crate) fn cat_projection( - &self, - node: &N, - base_place: PlaceWithHirId<'tcx>, - ty: Ty<'tcx>, - kind: ProjectionKind, - ) -> PlaceWithHirId<'tcx> { - let place_ty = base_place.place.ty(); - let mut projections = base_place.place.projections; - - let node_ty = self.typeck_results.node_type(node.hir_id()); - // Opaque types can't have field projections, but we can instead convert - // the current place in-place (heh) to the hidden type, and then apply all - // follow up projections on that. - if node_ty != place_ty && matches!(place_ty.kind(), ty::Alias(ty::Opaque, ..)) { - projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty }); - } - projections.push(Projection { kind, ty }); - PlaceWithHirId::new( - node.hir_id(), - base_place.place.base_ty, - base_place.place.base, - projections, - ) - } - - #[instrument(level = "debug", skip(self))] - fn cat_overloaded_place( - &self, - expr: &hir::Expr<'_>, - base: &hir::Expr<'_>, - ) -> McResult> { - // Reconstruct the output assuming it's a reference with the - // same region and mutability as the receiver. This holds for - // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. - let place_ty = self.expr_ty(expr)?; - let base_ty = self.expr_ty_adjusted(base)?; - - let ty::Ref(region, _, mutbl) = *base_ty.kind() else { - span_bug!(expr.span, "cat_overloaded_place: base is not a reference"); - }; - let ref_ty = Ty::new_ref(self.tcx(), region, place_ty, mutbl); - - let base = self.cat_rvalue(expr.hir_id, ref_ty); - self.cat_deref(expr, base) - } - - #[instrument(level = "debug", skip(self, node), ret)] - fn cat_deref( - &self, - node: &impl HirNode, - base_place: PlaceWithHirId<'tcx>, - ) -> McResult> { - let base_curr_ty = base_place.place.ty(); - let deref_ty = match base_curr_ty.builtin_deref(true) { - Some(mt) => mt.ty, - None => { - debug!("explicit deref of non-derefable type: {:?}", base_curr_ty); - return Err(()); - } - }; - let mut projections = base_place.place.projections; - projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty }); - - Ok(PlaceWithHirId::new( - node.hir_id(), - base_place.place.base_ty, - base_place.place.base, - projections, - )) - } - - pub(crate) fn cat_pattern( - &self, - place: PlaceWithHirId<'tcx>, - pat: &hir::Pat<'_>, - mut op: F, - ) -> McResult<()> - where - F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>), - { - self.cat_pattern_(place, pat, &mut op) - } - - /// Returns the variant index for an ADT used within a Struct or TupleStruct pattern - /// Here `pat_hir_id` is the HirId of the pattern itself. - fn variant_index_for_adt( - &self, - qpath: &hir::QPath<'_>, - pat_hir_id: HirId, - span: Span, - ) -> McResult { - let res = self.typeck_results.qpath_res(qpath, pat_hir_id); - let ty = self.typeck_results.node_type(pat_hir_id); - let ty::Adt(adt_def, _) = ty.kind() else { - self.tcx() - .dcx() - .span_delayed_bug(span, "struct or tuple struct pattern not applied to an ADT"); - return Err(()); - }; - - match res { - Res::Def(DefKind::Variant, variant_id) => Ok(adt_def.variant_index_with_id(variant_id)), - Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => { - Ok(adt_def.variant_index_with_ctor_id(variant_ctor_id)) - } - Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _) - | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) - | Res::SelfCtor(..) - | Res::SelfTyParam { .. } - | Res::SelfTyAlias { .. } => { - // Structs and Unions have only have one variant. - Ok(FIRST_VARIANT) - } - _ => bug!("expected ADT path, found={:?}", res), - } - } - - /// Returns the total number of fields in an ADT variant used within a pattern. - /// Here `pat_hir_id` is the HirId of the pattern itself. - fn total_fields_in_adt_variant( - &self, - pat_hir_id: HirId, - variant_index: VariantIdx, - span: Span, - ) -> McResult { - let ty = self.typeck_results.node_type(pat_hir_id); - match ty.kind() { - ty::Adt(adt_def, _) => Ok(adt_def.variant(variant_index).fields.len()), - _ => { - self.tcx() - .dcx() - .span_bug(span, "struct or tuple struct pattern not applied to an ADT"); - } - } - } - - /// Returns the total number of fields in a tuple used within a Tuple pattern. - /// Here `pat_hir_id` is the HirId of the pattern itself. - fn total_fields_in_tuple(&self, pat_hir_id: HirId, span: Span) -> McResult { - let ty = self.typeck_results.node_type(pat_hir_id); - match ty.kind() { - ty::Tuple(args) => Ok(args.len()), - _ => { - self.tcx().dcx().span_delayed_bug(span, "tuple pattern not applied to a tuple"); - Err(()) - } - } - } - - /// Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it - /// is being matched against. - /// - /// In general, the way that this works is that we walk down the pattern, - /// constructing a `PlaceWithHirId` that represents the path that will be taken - /// to reach the value being matched. - #[instrument(skip(self, op), ret, level = "debug")] - fn cat_pattern_( - &self, - mut place_with_id: PlaceWithHirId<'tcx>, - pat: &hir::Pat<'_>, - op: &mut F, - ) -> McResult<()> - where - F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>), - { - // If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly. - // `PlaceWithHirId`s are constructed differently from patterns. For example, in - // - // ``` - // match foo { - // &&Some(x, ) => { ... }, - // _ => { ... }, - // } - // ``` - // - // the pattern `&&Some(x,)` is represented as `Ref { Ref { TupleStruct }}`. To build the - // corresponding `PlaceWithHirId` we start with the `PlaceWithHirId` for `foo`, and then, by traversing the - // pattern, try to answer the question: given the address of `foo`, how is `x` reached? - // - // `&&Some(x,)` `place_foo` - // `&Some(x,)` `deref { place_foo}` - // `Some(x,)` `deref { deref { place_foo }}` - // `(x,)` `field0 { deref { deref { place_foo }}}` <- resulting place - // - // The above example has no adjustments. If the code were instead the (after adjustments, - // equivalent) version - // - // ``` - // match foo { - // Some(x, ) => { ... }, - // _ => { ... }, - // } - // ``` - // - // Then we see that to get the same result, we must start with - // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)` - // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`. - for _ in 0..self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len()) { - debug!("applying adjustment to place_with_id={:?}", place_with_id); - place_with_id = self.cat_deref(pat, place_with_id)?; - } - let place_with_id = place_with_id; // lose mutability - debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id); - - // Invoke the callback, but only now, after the `place_with_id` has adjusted. - // - // To see that this makes sense, consider `match &Some(3) { Some(x) => { ... }}`. In that - // case, the initial `place_with_id` will be that for `&Some(3)` and the pattern is `Some(x)`. We - // don't want to call `op` with these incompatible values. As written, what happens instead - // is that `op` is called with the adjusted place (that for `*&Some(3)`) and the pattern - // `Some(x)` (which matches). Recursing once more, `*&Some(3)` and the pattern `Some(x)` - // result in the place `Downcast(*&Some(3)).0` associated to `x` and invoke `op` with - // that (where the `ref` on `x` is implied). - op(&place_with_id, pat); - - match pat.kind { - PatKind::Tuple(subpats, dots_pos) => { - // (p1, ..., pN) - let total_fields = self.total_fields_in_tuple(pat.hir_id, pat.span)?; - - for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) { - let subpat_ty = self.pat_ty_adjusted(subpat)?; - let projection_kind = - ProjectionKind::Field(FieldIdx::from_usize(i), FIRST_VARIANT); - let sub_place = - self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind); - self.cat_pattern_(sub_place, subpat, op)?; - } - } - - PatKind::TupleStruct(ref qpath, subpats, dots_pos) => { - // S(p1, ..., pN) - let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?; - let total_fields = - self.total_fields_in_adt_variant(pat.hir_id, variant_index, pat.span)?; - - for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) { - let subpat_ty = self.pat_ty_adjusted(subpat)?; - let projection_kind = - ProjectionKind::Field(FieldIdx::from_usize(i), variant_index); - let sub_place = - self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind); - self.cat_pattern_(sub_place, subpat, op)?; - } - } - - PatKind::Struct(ref qpath, field_pats, _) => { - // S { f1: p1, ..., fN: pN } - - let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?; - - for fp in field_pats { - let field_ty = self.pat_ty_adjusted(fp.pat)?; - let field_index = self - .typeck_results - .field_indices() - .get(fp.hir_id) - .cloned() - .expect("no index for a field"); - - let field_place = self.cat_projection( - pat, - place_with_id.clone(), - field_ty, - ProjectionKind::Field(field_index, variant_index), - ); - self.cat_pattern_(field_place, fp.pat, op)?; - } - } - - PatKind::Or(pats) => { - for pat in pats { - self.cat_pattern_(place_with_id.clone(), pat, op)?; - } - } - - PatKind::Binding(.., Some(subpat)) => { - self.cat_pattern_(place_with_id, subpat, op)?; - } - - PatKind::Box(subpat) | PatKind::Ref(subpat, _) => { - // box p1, &p1, &mut p1. we can ignore the mutability of - // PatKind::Ref since that information is already contained - // in the type. - let subplace = self.cat_deref(pat, place_with_id)?; - self.cat_pattern_(subplace, subpat, op)?; - } - PatKind::Deref(subpat) => { - let mutable = self.typeck_results.pat_has_ref_mut_binding(subpat); - let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not }; - let re_erased = self.tcx().lifetimes.re_erased; - let ty = self.pat_ty_adjusted(subpat)?; - let ty = Ty::new_ref(self.tcx(), re_erased, ty, mutability); - // A deref pattern generates a temporary. - let place = self.cat_rvalue(pat.hir_id, ty); - self.cat_pattern_(place, subpat, op)?; - } - - PatKind::Slice(before, ref slice, after) => { - let Some(element_ty) = place_with_id.place.ty().builtin_index() else { - debug!("explicit index of non-indexable type {:?}", place_with_id); - return Err(()); - }; - let elt_place = self.cat_projection( - pat, - place_with_id.clone(), - element_ty, - ProjectionKind::Index, - ); - for before_pat in before { - self.cat_pattern_(elt_place.clone(), before_pat, op)?; - } - if let Some(slice_pat) = *slice { - let slice_pat_ty = self.pat_ty_adjusted(slice_pat)?; - let slice_place = self.cat_projection( - pat, - place_with_id, - slice_pat_ty, - ProjectionKind::Subslice, - ); - self.cat_pattern_(slice_place, slice_pat, op)?; - } - for after_pat in after { - self.cat_pattern_(elt_place.clone(), after_pat, op)?; - } - } - - PatKind::Path(_) - | PatKind::Binding(.., None) - | PatKind::Lit(..) - | PatKind::Range(..) - | PatKind::Never - | PatKind::Wild - | PatKind::Err(_) => { - // always ok - } - } - - Ok(()) - } -} diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index d57015282de9e..007ec7ff378ab 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -450,7 +450,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // `foo.bar::(...)` -- the `Self` type here will be the // type of `foo` (possibly adjusted), but we don't want to // include that. We want just the `[_, u32]` part. - if !args.is_empty() && !generics.params.is_empty() { + if !args.is_empty() && !generics.own_params.is_empty() { let user_type_annotation = self.probe(|_| { let user_args = UserArgs { args: GenericArgs::for_item(self.tcx, pick.item.def_id, |param, _| { @@ -564,16 +564,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // `self.add_required_obligations(self.span, def_id, &all_args);` for obligation in traits::predicates_for_generics( |idx, span| { - let code = if span.is_dummy() { - ObligationCauseCode::ExprItemObligation(def_id, self.call_expr.hir_id, idx) - } else { - ObligationCauseCode::ExprBindingObligation( - def_id, - span, - self.call_expr.hir_id, - idx, - ) - }; + let code = ObligationCauseCode::WhereClauseInExpr( + def_id, + span, + self.call_expr.hir_id, + idx, + ); traits::ObligationCause::new(self.span, self.body_id, code) }, self.param_env, @@ -589,7 +585,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // the function type must also be well-formed (this is not // implied by the args being well-formed because of inherent // impls and late-bound regions - see issue #28609). - self.register_wf_obligation(fty.into(), self.span, traits::WellFormed(None)); + self.register_wf_obligation(fty.into(), self.span, ObligationCauseCode::WellFormed(None)); } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 39d54f1a25e0b..ec613f3d14e72 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -315,7 +315,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trait_def_id: DefId, self_ty: Ty<'tcx>, opt_input_types: Option<&[Ty<'tcx>]>, - ) -> (traits::PredicateObligation<'tcx>, &'tcx ty::List>) { + ) -> (traits::PredicateObligation<'tcx>, ty::GenericArgsRef<'tcx>) { // Construct a trait-reference `self_ty : Trait` let args = GenericArgs::for_item(self.tcx, trait_def_id, |param, _| { match param.kind { @@ -365,7 +365,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { m_name: Ident, trait_def_id: DefId, obligation: traits::PredicateObligation<'tcx>, - args: &'tcx ty::List>, + args: ty::GenericArgsRef<'tcx>, ) -> Option>> { debug!(?obligation); diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs index 22eef8e53dae0..305aaf3b8ddd5 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs @@ -7,7 +7,6 @@ use hir::HirId; use hir::ItemKind; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_middle::ty::{self, Ty}; use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS; use rustc_span::symbol::kw::{Empty, Underscore}; @@ -218,8 +217,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If we know it does not, we don't need to warn. if method_name.name == sym::from_iter { if let Some(trait_def_id) = self.tcx.get_diagnostic_item(sym::FromIterator) { - let any_type = - self.infcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span }); + let any_type = self.infcx.next_ty_var(span); if !self .infcx .type_implements_trait(trait_def_id, [self_ty, any_type], self.param_env) @@ -251,23 +249,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id); let trait_generics = self.tcx.generics_of(container_id); - let trait_name = if trait_generics.params.len() <= trait_generics.has_self as usize - { - trait_path - } else { - let counts = trait_generics.own_counts(); - format!( - "{}<{}>", - trait_path, - std::iter::repeat("'_") - .take(counts.lifetimes) - .chain(std::iter::repeat("_").take( - counts.types + counts.consts - trait_generics.has_self as usize - )) - .collect::>() - .join(", ") - ) - }; + let trait_name = + if trait_generics.own_params.len() <= trait_generics.has_self as usize { + trait_path + } else { + let counts = trait_generics.own_counts(); + format!( + "{}<{}>", + trait_path, + std::iter::repeat("'_") + .take(counts.lifetimes) + .chain(std::iter::repeat("_").take( + counts.types + counts.consts - trait_generics.has_self as usize + )) + .collect::>() + .join(", ") + ) + }; let mut self_ty_name = self_ty_span .find_ancestor_inside(span) @@ -280,7 +278,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !self_ty_name.contains('<') { if let ty::Adt(def, _) = self_ty.kind() { let generics = self.tcx.generics_of(def.did()); - if !generics.params.is_empty() { + if !generics.own_params.is_empty() { let counts = generics.own_counts(); self_ty_name += &format!( "<{}>", diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 8a7ebd6478b13..e9446b862fa0d 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -15,6 +15,7 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; +use rustc_infer::traits::ObligationCauseCode; use rustc_middle::middle::stability; use rustc_middle::query::Providers; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; @@ -1400,16 +1401,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // Convert the bounds into obligations. ocx.register_obligations(traits::predicates_for_generics( |idx, span| { - let code = if span.is_dummy() { - traits::ExprItemObligation(impl_def_id, self.scope_expr_id, idx) - } else { - traits::ExprBindingObligation( - impl_def_id, - span, - self.scope_expr_id, - idx, - ) - }; + let code = ObligationCauseCode::WhereClauseInExpr( + impl_def_id, + span, + self.scope_expr_id, + idx, + ); ObligationCause::new(self.span, self.body_id, code) }, self.param_env, @@ -1735,7 +1732,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let generics = self.tcx.generics_of(method); assert_eq!(args.len(), generics.parent_count); - let xform_fn_sig = if generics.params.is_empty() { + let xform_fn_sig = if generics.own_params.is_empty() { fn_sig.instantiate(self.tcx, args) } else { let args = GenericArgs::for_item(self.tcx, method, |param, _| { diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 078009515e428..0483bd0357675 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -22,11 +22,12 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::PatKind::Binding; use rustc_hir::PathSegment; use rustc_hir::{ExprKind, Node, QPath}; -use rustc_infer::infer::{self, type_variable::TypeVariableOrigin, RegionVariableOrigin}; -use rustc_middle::infer::unify_key::ConstVariableOrigin; +use rustc_infer::infer::{self, RegionVariableOrigin}; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; -use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths}; +use rustc_middle::ty::print::{ + with_crate_prefix, with_forced_trimmed_paths, PrintTraitRefExt as _, +}; use rustc_middle::ty::IsSuggestable; use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::def_id::DefIdSet; @@ -75,11 +76,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.autoderef(span, ty).any(|(ty, _)| { info!("check deref {:?} impl FnOnce", ty); self.probe(|_| { - let trait_ref = ty::TraitRef::new( - tcx, - fn_once, - [ty, self.next_ty_var(TypeVariableOrigin { param_def_id: None, span })], - ); + let trait_ref = + ty::TraitRef::new(tcx, fn_once, [ty, self.next_ty_var(span)]); let poly_trait_ref = ty::Binder::dummy(trait_ref); let obligation = Obligation::misc( tcx, @@ -150,7 +148,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; }; let trait_ref = ty::TraitRef::new(self.tcx, into_iterator_trait, [ty]); - let cause = ObligationCause::new(span, self.body_id, ObligationCauseCode::MiscObligation); + let cause = ObligationCause::new(span, self.body_id, ObligationCauseCode::Misc); let obligation = Obligation::new(self.tcx, cause, self.param_env, trait_ref); if !self.predicate_must_hold_modulo_regions(&obligation) { return false; @@ -830,13 +828,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Extract the predicate span and parent def id of the cause, // if we have one. let (item_def_id, cause_span) = match cause.as_ref().map(|cause| cause.code()) { - Some(ObligationCauseCode::ImplDerivedObligation(data)) => { + Some(ObligationCauseCode::ImplDerived(data)) => { (data.impl_or_alias_def_id, data.span) } Some( - ObligationCauseCode::ExprBindingObligation(def_id, span, _, _) - | ObligationCauseCode::BindingObligation(def_id, span), - ) => (*def_id, *span), + ObligationCauseCode::WhereClauseInExpr(def_id, span, _, _) + | ObligationCauseCode::WhereClause(def_id, span), + ) if !span.is_dummy() => (*def_id, *span), _ => continue, }; @@ -1259,12 +1257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args.map(|args| { args.iter() .map(|expr| { - self.node_ty_opt(expr.hir_id).unwrap_or_else(|| { - self.next_ty_var(TypeVariableOrigin { - param_def_id: None, - span: expr.span, - }) - }) + self.node_ty_opt(expr.hir_id).unwrap_or_else(|| self.next_ty_var(expr.span)) }) .collect() }), @@ -1846,18 +1839,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { GenericArgKind::Lifetime(_) => self .next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP)) .into(), - GenericArgKind::Type(_) => self - .next_ty_var(TypeVariableOrigin { - span: DUMMY_SP, - param_def_id: None, - }) - .into(), - GenericArgKind::Const(arg) => self - .next_const_var( - arg.ty(), - ConstVariableOrigin { span: DUMMY_SP, param_def_id: None }, - ) - .into(), + GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(), + GenericArgKind::Const(arg) => { + self.next_const_var(arg.ty(), DUMMY_SP).into() + } } } else { arg diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index a4f840d849dd2..dca1cda069408 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -7,7 +7,6 @@ use rustc_ast as ast; use rustc_data_structures::packed::Pu128; use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag}; use rustc_hir as hir; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::traits::ObligationCauseCode; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, @@ -20,7 +19,7 @@ use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt}; +use rustc_trait_selection::traits::{FulfillmentError, ObligationCtxt}; use rustc_type_ir::TyKind::*; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -219,8 +218,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // e.g., adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result // in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`. let lhs_ty = self.check_expr(lhs_expr); - let fresh_var = self - .next_ty_var(TypeVariableOrigin { param_def_id: None, span: lhs_expr.span }); + let fresh_var = self.next_ty_var(lhs_expr.span); self.demand_coerce(lhs_expr, lhs_ty, fresh_var, Some(rhs_expr), AllowTwoPhase::No) } IsAssign::Yes => { @@ -239,8 +237,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // using this variable as the expected type, which sometimes lets // us do better coercions than we would be able to do otherwise, // particularly for things like `String + &String`. - let rhs_ty_var = - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: rhs_expr.span }); + let rhs_ty_var = self.next_ty_var(rhs_expr.span); let result = self.lookup_op_method( (lhs_expr, lhs_ty), @@ -887,7 +884,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let input_types = opt_rhs_ty.as_slice(); let cause = self.cause( span, - traits::BinOp { + ObligationCauseCode::BinOp { lhs_hir_id: lhs_expr.hir_id, rhs_hir_id: opt_rhs_expr.map(|expr| expr.hir_id), rhs_span: opt_rhs_expr.map(|expr| expr.span), diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 8c7ae7f8e980d..b77f91dd544c1 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -9,7 +9,6 @@ use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, Pat, PatKind}; use rustc_infer::infer; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; @@ -19,7 +18,7 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, Span, DUMMY_SP}; use rustc_target::abi::FieldIdx; -use rustc_trait_selection::traits::{ObligationCause, Pattern}; +use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; use ty::VariantDef; use std::cmp; @@ -74,23 +73,28 @@ struct TopInfo<'tcx> { /// found type `std::result::Result<_, _>` /// ``` span: Option, + /// The [`HirId`] of the top-level pattern. + hir_id: HirId, } #[derive(Copy, Clone)] struct PatInfo<'tcx, 'a> { binding_mode: ByRef, - max_ref_mutbl: Mutability, - top_info: TopInfo<'tcx>, - decl_origin: Option>, + max_ref_mutbl: MutblCap, + top_info: &'a TopInfo<'tcx>, + decl_origin: Option>, /// The depth of current pattern current_depth: u32, } impl<'tcx> FnCtxt<'_, 'tcx> { - fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> { - let code = - Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr.is_some() }; + fn pattern_cause(&self, ti: &TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> { + let code = ObligationCauseCode::Pattern { + span: ti.span, + root_ty: ti.expected, + origin_expr: ti.origin_expr.is_some(), + }; self.cause(cause_span, code) } @@ -99,7 +103,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { cause_span: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, - ti: TopInfo<'tcx>, + ti: &TopInfo<'tcx>, ) -> Option> { let mut diag = self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)?; @@ -116,7 +120,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { cause_span: Span, expected: Ty<'tcx>, actual: Ty<'tcx>, - ti: TopInfo<'tcx>, + ti: &TopInfo<'tcx>, ) { if let Some(err) = self.demand_eqtype_pat_diag(cause_span, expected, actual, ti) { err.emit(); @@ -125,22 +129,61 @@ impl<'tcx> FnCtxt<'_, 'tcx> { } /// Mode for adjusting the expected type and binding mode. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] enum AdjustMode { /// Peel off all immediate reference types. Peel, /// Reset binding mode to the initial mode. /// Used for destructuring assignment, where we don't want any match ergonomics. Reset, - /// Produced by ref patterns. - /// Reset the binding mode to the initial mode, - /// and if the old biding mode was by-reference - /// with mutability matching the pattern, - /// mark the pattern as having consumed this reference. - ResetAndConsumeRef(Mutability), /// Pass on the input binding mode and expected type. Pass, } +/// `ref mut` patterns (explicit or match-ergonomics) +/// are not allowed behind an `&` reference. +/// +/// This includes explicit `ref mut` behind `&` patterns +/// that match against `&mut` references, +/// where the code would have compiled +/// had the pattern been written as `&mut`. +/// However, the borrow checker will not catch +/// this last case, so we need to throw an error ourselves. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum MutblCap { + /// Mutability restricted to immutable. + Not, + + /// Mutability restricted to immutable, but only because of the pattern + /// (not the scrutinee type). + /// + /// The contained span, if present, points to an `&` pattern + /// that is the reason for the restriction, + /// and which will be reported in a diagnostic. + WeaklyNot(Option), + + /// No restriction on mutability + Mut, +} + +impl MutblCap { + #[must_use] + fn cap_to_weakly_not(self, span: Option) -> Self { + match self { + MutblCap::Not => MutblCap::Not, + _ => MutblCap::WeaklyNot(span), + } + } + + #[must_use] + fn as_mutbl(self) -> Mutability { + match self { + MutblCap::Not | MutblCap::WeaklyNot(_) => Mutability::Not, + MutblCap::Mut => Mutability::Mut, + } + } +} + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Type check the given top level pattern against the `expected` type. /// @@ -158,11 +201,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { origin_expr: Option<&'tcx hir::Expr<'tcx>>, decl_origin: Option>, ) { - let info = TopInfo { expected, origin_expr, span }; + let info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id }; let pat_info = PatInfo { binding_mode: ByRef::No, - max_ref_mutbl: Mutability::Mut, - top_info: info, + max_ref_mutbl: MutblCap::Mut, + top_info: &info, decl_origin, current_depth: 0, }; @@ -170,14 +213,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Type check the given `pat` against the `expected` type - /// with the provided `def_bm` (default binding mode). + /// with the provided `binding_mode` (default binding mode). /// /// Outside of this module, `check_pat_top` should always be used. /// Conversely, inside this module, `check_pat_top` should never be used. #[instrument(level = "debug", skip(self, pat_info))] fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) { - let PatInfo { binding_mode: def_bm, max_ref_mutbl, top_info: ti, current_depth, .. } = - pat_info; + let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info; let path_res = match &pat.kind { PatKind::Path(qpath) => Some( @@ -186,10 +228,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => None, }; let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res)); - let (expected, def_bm, max_ref_mutbl, ref_pattern_already_consumed) = - self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode, max_ref_mutbl); + let (expected, binding_mode, max_ref_mutbl) = + self.calc_default_binding_mode(pat, expected, binding_mode, adjust_mode, max_ref_mutbl); let pat_info = PatInfo { - binding_mode: def_bm, + binding_mode, max_ref_mutbl, top_info: ti, decl_origin: pat_info.decl_origin, @@ -202,8 +244,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatKind::Never => expected, PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti), PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti), - PatKind::Binding(ba, var_id, _, sub) => { - self.check_pat_ident(pat, ba, var_id, sub, expected, pat_info) + PatKind::Binding(ba, var_id, ident, sub) => { + self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info) } PatKind::TupleStruct(ref qpath, subpats, ddpos) => { self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info) @@ -225,14 +267,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info), PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info), - PatKind::Ref(inner, mutbl) => self.check_pat_ref( - pat, - inner, - mutbl, - expected, - pat_info, - ref_pattern_already_consumed, - ), + PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info), PatKind::Slice(before, slice, after) => { self.check_pat_slice(pat.span, before, slice, after, expected, pat_info) } @@ -285,52 +320,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Compute the new expected type and default binding mode from the old ones /// as well as the pattern form we are currently checking. - /// - /// Last entry is only relevant for ref patterns (`&` and `&mut`); - /// if `true`, then the ref pattern consumed a match ergonomics inserted reference - /// and so does no need to match against a reference in the scrutinee type. fn calc_default_binding_mode( &self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, def_br: ByRef, adjust_mode: AdjustMode, - max_ref_mutbl: Mutability, - ) -> (Ty<'tcx>, ByRef, Mutability, bool) { - if let ByRef::Yes(mutbl) = def_br { - debug_assert!(mutbl <= max_ref_mutbl); + max_ref_mutbl: MutblCap, + ) -> (Ty<'tcx>, ByRef, MutblCap) { + if let ByRef::Yes(Mutability::Mut) = def_br { + debug_assert!(max_ref_mutbl == MutblCap::Mut); } match adjust_mode { - AdjustMode::Pass => (expected, def_br, max_ref_mutbl, false), - AdjustMode::Reset => (expected, ByRef::No, Mutability::Mut, false), - AdjustMode::ResetAndConsumeRef(ref_pat_mutbl) => { - let mutbls_match = def_br == ByRef::Yes(ref_pat_mutbl); - if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 { - if mutbls_match { - debug!("consuming inherited reference"); - (expected, ByRef::No, cmp::min(max_ref_mutbl, ref_pat_mutbl), true) - } else { - let (new_ty, new_bm, max_ref_mutbl) = if ref_pat_mutbl == Mutability::Mut { - self.peel_off_references( - pat, - expected, - def_br, - Mutability::Not, - max_ref_mutbl, - ) - } else { - (expected, def_br.cap_ref_mutability(Mutability::Not), Mutability::Not) - }; - (new_ty, new_bm, max_ref_mutbl, false) - } - } else { - (expected, ByRef::No, max_ref_mutbl, mutbls_match) - } - } + AdjustMode::Pass => (expected, def_br, max_ref_mutbl), + AdjustMode::Reset => (expected, ByRef::No, MutblCap::Mut), AdjustMode::Peel => { - let peeled = - self.peel_off_references(pat, expected, def_br, Mutability::Mut, max_ref_mutbl); - (peeled.0, peeled.1, peeled.2, false) + self.peel_off_references(pat, expected, def_br, Mutability::Mut, max_ref_mutbl) } } } @@ -376,17 +381,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // a reference type wherefore peeling doesn't give up any expressiveness. _ => AdjustMode::Peel, }, - // When encountering a `& mut? pat` pattern, reset to "by value". - // This is so that `x` and `y` here are by value, as they appear to be: - // - // ``` - // match &(&22, &44) { - // (&x, &y) => ... - // } - // ``` - // - // See issue #46688. - PatKind::Ref(_, mutbl) => AdjustMode::ResetAndConsumeRef(*mutbl), + // Ref patterns are complicated, we handle them in `check_pat_ref`. + PatKind::Ref(..) => AdjustMode::Pass, // A `_` pattern works with any expected type, so there's no need to do anything. PatKind::Wild // A malformed pattern doesn't have an expected type, so let's just accept any type. @@ -412,8 +408,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, mut def_br: ByRef, max_peelable_mutability: Mutability, - mut max_ref_mutability: Mutability, - ) -> (Ty<'tcx>, ByRef, Mutability) { + mut max_ref_mutability: MutblCap, + ) -> (Ty<'tcx>, ByRef, MutblCap) { let mut expected = self.try_structurally_resolve_type(pat.span, expected); // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example, // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches @@ -447,9 +443,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 { - def_br = def_br.cap_ref_mutability(max_ref_mutability); + def_br = def_br.cap_ref_mutability(max_ref_mutability.as_mutbl()); if def_br == ByRef::Yes(Mutability::Not) { - max_ref_mutability = Mutability::Not; + max_ref_mutability = MutblCap::Not; } } @@ -469,7 +465,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, lt: &hir::Expr<'tcx>, expected: Ty<'tcx>, - ti: TopInfo<'tcx>, + ti: &TopInfo<'tcx>, ) -> Ty<'tcx> { // We've already computed the type above (when checking for a non-ref pat), // so avoid computing it again. @@ -539,7 +535,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs: Option<&'tcx hir::Expr<'tcx>>, rhs: Option<&'tcx hir::Expr<'tcx>>, expected: Ty<'tcx>, - ti: TopInfo<'tcx>, + ti: &TopInfo<'tcx>, ) -> Ty<'tcx> { let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr { None => None, @@ -666,8 +662,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_pat_ident( &self, pat: &'tcx Pat<'tcx>, - ba: BindingMode, + user_bind_annot: BindingMode, var_id: HirId, + ident: Ident, sub: Option<&'tcx Pat<'tcx>>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>, @@ -675,24 +672,44 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info; // Determine the binding mode... - let bm = match ba { + let bm = match user_bind_annot { + // `mut` resets binding mode on edition <= 2021 BindingMode(ByRef::No, Mutability::Mut) if !(pat.span.at_least_rust_2024() && self.tcx.features().mut_preserve_binding_mode_2024) && matches!(def_br, ByRef::Yes(_)) => { - // `mut x` resets the binding mode in edition <= 2021. - self.tcx.emit_node_span_lint( - rustc_lint::builtin::DEREFERENCING_MUT_BINDING, - pat.hir_id, - pat.span, - errors::DereferencingMutBinding { span: pat.span }, - ); + self.typeck_results + .borrow_mut() + .rust_2024_migration_desugared_pats_mut() + .insert(pat_info.top_info.hir_id); BindingMode(ByRef::No, Mutability::Mut) } BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl), - BindingMode(ByRef::Yes(_), _) => ba, + BindingMode(ByRef::Yes(_), _) => user_bind_annot, }; + + if bm.0 == ByRef::Yes(Mutability::Mut) + && let MutblCap::WeaklyNot(and_pat_span) = pat_info.max_ref_mutbl + { + let mut err = struct_span_code_err!( + self.tcx.dcx(), + ident.span, + E0596, + "cannot borrow as mutable inside an `&` pattern" + ); + + if let Some(span) = and_pat_span { + err.span_suggestion( + span, + "replace this `&` with `&mut`", + "&mut ", + Applicability::MachineApplicable, + ); + } + err.emit(); + } + // ...and store it in a side table: self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm); @@ -718,7 +735,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If there are multiple arms, make sure they all agree on // what the type of the binding `x` ought to be. if var_id != pat.hir_id { - self.check_binding_alt_eq_ty(ba, pat.span, var_id, local_ty, ti); + self.check_binding_alt_eq_ty(user_bind_annot, pat.span, var_id, local_ty, ti); } if let Some(p) = sub { @@ -737,7 +754,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, var_id: HirId, ty: Ty<'tcx>, - ti: TopInfo<'tcx>, + ti: &TopInfo<'tcx>, ) { let var_ty = self.local_ty(span, var_id); if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) { @@ -919,8 +936,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inner: &Pat<'_>, ) -> Result<(), ErrorGuaranteed> { if let PatKind::Binding(..) = inner.kind - && let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) - && let ty::Dynamic(..) = mt.ty.kind() + && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true) + && let ty::Dynamic(..) = pointee_ty.kind() { // This is "x = dyn SomeTrait" being reduced from // "let &x = &dyn SomeTrait" or "let box x = Box", an error. @@ -979,7 +996,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { qpath: &hir::QPath<'_>, path_resolution: (Res, Option>, &'tcx [hir::PathSegment<'tcx>]), expected: Ty<'tcx>, - ti: TopInfo<'tcx>, + ti: &TopInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; @@ -1419,8 +1436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let max_len = cmp::max(expected_len, elements.len()); - let element_tys_iter = - (0..max_len).map(|_| self.next_ty_var(TypeVariableOrigin { param_def_id: None, span })); + let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(span)); let element_tys = tcx.mk_type_list_from_iter(element_tys_iter); let pat_ty = Ty::new_tup(tcx, element_tys); if let Some(err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, pat_info.top_info) { @@ -1676,7 +1692,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { unmentioned_fields: &mut Vec<(&'tcx ty::FieldDef, Ident)>, pat: &'tcx Pat<'tcx>, variant: &ty::VariantDef, - args: &'tcx ty::List>, + args: ty::GenericArgsRef<'tcx>, ) -> Diag<'tcx> { let tcx = self.tcx; let (field_names, t, plural) = if let [field] = inexistent_fields { @@ -2046,8 +2062,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(()) => { // Here, `demand::subtype` is good enough, but I don't // think any errors can be introduced by using `demand::eqtype`. - let inner_ty = - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: inner.span }); + let inner_ty = self.next_ty_var(inner.span); let box_ty = Ty::new_box(tcx, inner_ty); self.demand_eqtype_pat(span, expected, box_ty, pat_info.top_info); (box_ty, inner_ty) @@ -2105,75 +2120,145 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, pat: &'tcx Pat<'tcx>, inner: &'tcx Pat<'tcx>, - mutbl: Mutability, - expected: Ty<'tcx>, - pat_info: PatInfo<'tcx, '_>, - consumed_inherited_ref: bool, + pat_mutbl: Mutability, + mut expected: Ty<'tcx>, + mut pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - if consumed_inherited_ref - && pat.span.at_least_rust_2024() - && self.tcx.features().ref_pat_eat_one_layer_2024 - { - self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); - self.check_pat(inner, expected, pat_info); - expected + // FIXME: repace with `bool` once final decision on 1 vs 2 layers is made + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + enum MatchErgonomicsMode { + EatOneLayer, + EatTwoLayers, + Legacy, + } + + let match_ergonomics_mode = + if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 { + MatchErgonomicsMode::EatOneLayer + } else if self.tcx.features().ref_pat_everywhere { + MatchErgonomicsMode::EatTwoLayers + } else { + MatchErgonomicsMode::Legacy + }; + + let mut inherited_ref_mutbl_match = false; + if match_ergonomics_mode != MatchErgonomicsMode::Legacy { + if pat_mutbl == Mutability::Not { + // Prevent the inner pattern from binding with `ref mut`. + pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not( + inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end)), + ); + } + + if let ByRef::Yes(inh_mut) = pat_info.binding_mode { + inherited_ref_mutbl_match = pat_mutbl <= inh_mut; + } + + if inherited_ref_mutbl_match { + pat_info.binding_mode = ByRef::No; + if match_ergonomics_mode == MatchErgonomicsMode::EatOneLayer { + self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); + self.check_pat(inner, expected, pat_info); + return expected; + } + } else if match_ergonomics_mode == MatchErgonomicsMode::EatOneLayer + && pat_mutbl == Mutability::Mut + { + // `&mut` patterns pell off `&` references + let (new_expected, new_bm, max_ref_mutbl) = self.peel_off_references( + pat, + expected, + pat_info.binding_mode, + Mutability::Not, + pat_info.max_ref_mutbl, + ); + expected = new_expected; + pat_info.binding_mode = new_bm; + pat_info.max_ref_mutbl = max_ref_mutbl; + } } else { - let tcx = self.tcx; - let expected = self.shallow_resolve(expected); - let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) { - Ok(()) => { - // `demand::subtype` would be good enough, but using `eqtype` turns - // out to be equally general. See (note_1) for details. - - // Take region, inner-type from expected type if we can, - // to avoid creating needless variables. This also helps with - // the bad interactions of the given hack detailed in (note_1). - debug!("check_pat_ref: expected={:?}", expected); - match *expected.kind() { - ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty), - _ => { - if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere { - // We already matched against a match-ergonmics inserted reference, - // so we don't need to match against a reference from the original type. - // Save this infor for use in lowering later - self.typeck_results - .borrow_mut() - .skipped_ref_pats_mut() - .insert(pat.hir_id); - (expected, expected) - } else { - let inner_ty = self.next_ty_var(TypeVariableOrigin { - param_def_id: None, - span: inner.span, - }); - let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty); - debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty); - let err = self.demand_eqtype_pat_diag( - pat.span, - expected, - ref_ty, - pat_info.top_info, - ); + // Reset binding mode on old editions - // Look for a case like `fn foo(&foo: u32)` and suggest - // `fn foo(foo: &u32)` - if let Some(mut err) = err { - self.borrow_pat_suggestion(&mut err, pat); - err.emit(); - } - (ref_ty, inner_ty) - } + if pat_info.binding_mode != ByRef::No { + pat_info.binding_mode = ByRef::No; + + self.typeck_results + .borrow_mut() + .rust_2024_migration_desugared_pats_mut() + .insert(pat_info.top_info.hir_id); + } + + pat_info.max_ref_mutbl = MutblCap::Mut; + } + + let tcx = self.tcx; + expected = self.try_structurally_resolve_type(pat.span, expected); + let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) { + Ok(()) => { + // `demand::subtype` would be good enough, but using `eqtype` turns + // out to be equally general. See (note_1) for details. + + // Take region, inner-type from expected type if we can, + // to avoid creating needless variables. This also helps with + // the bad interactions of the given hack detailed in (note_1). + debug!("check_pat_ref: expected={:?}", expected); + match *expected.kind() { + ty::Ref(_, r_ty, r_mutbl) if r_mutbl == pat_mutbl => { + if r_mutbl == Mutability::Not + && match_ergonomics_mode != MatchErgonomicsMode::Legacy + { + pat_info.max_ref_mutbl = MutblCap::Not; } + + (expected, r_ty) + } + + // `&` pattern eats `&mut` reference + ty::Ref(_, r_ty, Mutability::Mut) + if pat_mutbl == Mutability::Not + && match_ergonomics_mode != MatchErgonomicsMode::Legacy => + { + (expected, r_ty) + } + + _ if inherited_ref_mutbl_match + && match_ergonomics_mode == MatchErgonomicsMode::EatTwoLayers => + { + // We already matched against a match-ergonmics inserted reference, + // so we don't need to match against a reference from the original type. + // Save this info for use in lowering later + self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); + (expected, expected) + } + + _ => { + let inner_ty = self.next_ty_var(inner.span); + let ref_ty = self.new_ref_ty(pat.span, pat_mutbl, inner_ty); + debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty); + let err = self.demand_eqtype_pat_diag( + pat.span, + expected, + ref_ty, + pat_info.top_info, + ); + + // Look for a case like `fn foo(&foo: u32)` and suggest + // `fn foo(foo: &u32)` + if let Some(mut err) = err { + self.borrow_pat_suggestion(&mut err, pat); + err.emit(); + } + (ref_ty, inner_ty) } } - Err(guar) => { - let err = Ty::new_error(tcx, guar); - (err, err) - } - }; - self.check_pat(inner, inner_ty, pat_info); - ref_ty - } + } + Err(guar) => { + let err = Ty::new_error(tcx, guar); + (err, err) + } + }; + self.check_pat(inner, inner_ty, pat_info); + ref_ty } /// Create a reference type with a fresh region variable. @@ -2194,8 +2279,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; let len = before.len(); - let ty_var_origin = TypeVariableOrigin { param_def_id: None, span }; - let inner_ty = self.next_ty_var(ty_var_origin); + let inner_ty = self.next_ty_var(span); Some(Ty::new_array(tcx, inner_ty, len.try_into().unwrap())) } diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs index bce43b3be3434..374279722ba28 100644 --- a/compiler/rustc_hir_typeck/src/place_op.rs +++ b/compiler/rustc_hir_typeck/src/place_op.rs @@ -4,7 +4,6 @@ use rustc_ast as ast; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir_analysis::autoderef::Autoderef; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::InferOk; use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCoercion}; use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; @@ -20,8 +19,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { oprnd_expr: &'tcx hir::Expr<'tcx>, oprnd_ty: Ty<'tcx>, ) -> Option> { - if let Some(mt) = oprnd_ty.builtin_deref(true) { - return Some(mt.ty); + if let Some(ty) = oprnd_ty.builtin_deref(true) { + return Some(ty); } let ok = self.try_overloaded_deref(expr.span, oprnd_ty)?; @@ -37,7 +36,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { span_bug!(expr.span, "input to deref is not a ref?"); } - let ty = self.make_overloaded_place_return_type(method).ty; + let ty = self.make_overloaded_place_return_type(method); self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); Some(ty) } @@ -147,8 +146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If some lookup succeeds, write callee into table and extract index/element // type from the method signature. // If some lookup succeeded, install method in table - let input_ty = - self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: base_expr.span }); + let input_ty = self.next_ty_var(base_expr.span); let method = self.try_overloaded_place_op(expr.span, self_ty, &[input_ty], PlaceOp::Index); @@ -175,7 +173,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method); - return Some((input_ty, self.make_overloaded_place_return_type(method).ty)); + return Some((input_ty, self.make_overloaded_place_return_type(method))); } } @@ -344,8 +342,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .borrow() .expr_ty_adjusted(base_expr) .builtin_deref(false) - .expect("place op takes something that is not a ref") - .ty; + .expect("place op takes something that is not a ref"); let arg_ty = match op { PlaceOp::Deref => None, diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 2bf4f51a8038a..819a8b661167c 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -252,12 +252,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - euv::ExprUseVisitor::new( + let _ = euv::ExprUseVisitor::new( + &FnCtxt::new(self, self.tcx.param_env(closure_def_id), closure_def_id), &mut delegate, - &self.infcx, - closure_def_id, - self.param_env, - &self.typeck_results.borrow(), ) .consume_body(body); diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 0a40ffb0d5aab..45f8fa77e56f8 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -346,6 +346,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { _ => {} }; + self.visit_rust_2024_migration_desugared_pats(p.hir_id); self.visit_skipped_ref_pats(p.hir_id); self.visit_pat_adjustments(p.span, p.hir_id); @@ -655,6 +656,22 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + #[instrument(skip(self), level = "debug")] + fn visit_rust_2024_migration_desugared_pats(&mut self, hir_id: hir::HirId) { + if self + .fcx + .typeck_results + .borrow_mut() + .rust_2024_migration_desugared_pats_mut() + .remove(hir_id) + { + debug!( + "node is a pat whose match ergonomics are desugared by the Rust 2024 migration lint" + ); + self.typeck_results.rust_2024_migration_desugared_pats_mut().insert(hir_id); + } + } + #[instrument(skip(self, span), level = "debug")] fn visit_pat_adjustments(&mut self, span: Span, hir_id: HirId) { let adjustment = self.fcx.typeck_results.borrow_mut().pat_adjustments_mut().remove(hir_id); diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs index 70d94873530e7..c7f07ebed973f 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_infer/src/errors/note_and_explain.rs @@ -69,16 +69,8 @@ impl<'a> DescriptionCtx<'a> { ty::RePlaceholder(_) | ty::ReError(_) => return None, - // FIXME(#13998) RePlaceholder should probably print like - // ReLateParam rather than dumping Debug output on the user. - // - // We shouldn't really be having unification failures with ReVar - // and ReBound though. - // - // FIXME(@lcnr): figure out why we have to handle `ReBound` - // here, this feels somewhat off. ty::ReVar(_) | ty::ReBound(..) | ty::ReErased => { - (alt_span, "revar", format!("{region:?}")) + bug!("unexpected region for DescriptionCtx: {:?}", region); } }; Some(DescriptionCtx { span, kind, arg }) diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 734fa919eb5c0..1abb8086d41c1 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -21,8 +21,7 @@ //! //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html -use crate::infer::ConstVariableOrigin; -use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin}; +use crate::infer::{InferCtxt, RegionVariableOrigin}; use rustc_index::IndexVec; use rustc_middle::infer::unify_key::EffectVarValue; use rustc_middle::ty::fold::TypeFoldable; @@ -114,10 +113,9 @@ impl<'tcx> InferCtxt<'tcx> { match cv_info.kind { CanonicalVarKind::Ty(ty_kind) => { let ty = match ty_kind { - CanonicalTyVarKind::General(ui) => self.next_ty_var_in_universe( - TypeVariableOrigin { param_def_id: None, span }, - universe_map(ui), - ), + CanonicalTyVarKind::General(ui) => { + self.next_ty_var_in_universe(span, universe_map(ui)) + } CanonicalTyVarKind::Int => self.next_int_var(), @@ -145,13 +143,9 @@ impl<'tcx> InferCtxt<'tcx> { ty::Region::new_placeholder(self.tcx, placeholder_mapped).into() } - CanonicalVarKind::Const(ui, ty) => self - .next_const_var_in_universe( - ty, - ConstVariableOrigin { param_def_id: None, span }, - universe_map(ui), - ) - .into(), + CanonicalVarKind::Const(ui, ty) => { + self.next_const_var_in_universe(ty, span, universe_map(ui)).into() + } CanonicalVarKind::Effect => { let vid = self .inner diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 635bbca37ecc2..3488517a4ef9b 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -70,7 +70,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_macros::extension; use rustc_middle::dep_graph::DepContext; -use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError}; +use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError, PrintTraitRefExt as _}; use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{ @@ -172,11 +172,9 @@ pub(super) fn note_and_explain_region<'tcx>( ty::ReError(_) => return, - // We shouldn't really be having unification failures with ReVar - // and ReBound though. - // - // FIXME(@lcnr): Figure out whether this is reachable and if so, why. - ty::ReVar(_) | ty::ReBound(..) | ty::ReErased => (format!("lifetime `{region}`"), alt_span), + ty::ReVar(_) | ty::ReBound(..) | ty::ReErased => { + bug!("unexpected region for note_and_explain_region: {:?}", region); + } }; emit_msg_span(err, prefix, description, span, suffix); @@ -885,9 +883,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { err.help("...or use `match` instead of `let...else`"); } _ => { - if let ObligationCauseCode::BindingObligation(_, span) - | ObligationCauseCode::ExprBindingObligation(_, span, ..) = + if let ObligationCauseCode::WhereClause(_, span) + | ObligationCauseCode::WhereClauseInExpr(_, span, ..) = cause.code().peel_derives() + && !span.is_dummy() && let TypeError::RegionsPlaceholderMismatch = terr { err.span_note(*span, "the lifetime requirement is introduced here"); @@ -2014,7 +2013,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { trace: &TypeTrace<'tcx>, terr: TypeError<'tcx>, ) -> Vec { - use crate::traits::ObligationCauseCode::{BlockTailExpression, MatchExpressionArm}; let mut suggestions = Vec::new(); let span = trace.cause.span(); let values = self.resolve_vars_if_possible(trace.values); @@ -2081,8 +2079,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } let code = trace.cause.code(); - if let &(MatchExpressionArm(box MatchExpressionArmCause { source, .. }) - | BlockTailExpression(.., source)) = code + if let &(ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { + source, + .. + }) + | ObligationCauseCode::BlockTailExpression(.., source)) = code && let hir::MatchSource::TryDesugar(_) = source && let Some((expected_ty, found_ty, _)) = self.values_str(trace.values) { @@ -2507,7 +2508,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let generics = self.tcx.generics_of(lifetime_scope); let mut used_names = iter::successors(Some(generics), |g| g.parent.map(|p| self.tcx.generics_of(p))) - .flat_map(|g| &g.params) + .flat_map(|g| &g.own_params) .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime)) .map(|p| p.name) .collect::>(); @@ -2775,19 +2776,17 @@ pub enum FailureCode { #[extension(pub trait ObligationCauseExt<'tcx>)] impl<'tcx> ObligationCause<'tcx> { fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode { - use self::FailureCode::*; - use crate::traits::ObligationCauseCode::*; match self.code() { - IfExpressionWithNoElse => Error0317, - MainFunctionType => Error0580, - CompareImplItemObligation { .. } - | MatchExpressionArm(_) - | IfExpression { .. } - | LetElse - | StartFunctionType - | LangFunctionType(_) - | IntrinsicType - | MethodReceiver => Error0308, + ObligationCauseCode::IfExpressionWithNoElse => FailureCode::Error0317, + ObligationCauseCode::MainFunctionType => FailureCode::Error0580, + ObligationCauseCode::CompareImplItem { .. } + | ObligationCauseCode::MatchExpressionArm(_) + | ObligationCauseCode::IfExpression { .. } + | ObligationCauseCode::LetElse + | ObligationCauseCode::StartFunctionType + | ObligationCauseCode::LangFunctionType(_) + | ObligationCauseCode::IntrinsicType + | ObligationCauseCode::MethodReceiver => FailureCode::Error0308, // In the case where we have no more specific thing to // say, also take a look at the error code, maybe we can @@ -2796,10 +2795,10 @@ impl<'tcx> ObligationCause<'tcx> { TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() => { - Error0644 + FailureCode::Error0644 } - TypeError::IntrinsicCast => Error0308, - _ => Error0308, + TypeError::IntrinsicCast => FailureCode::Error0308, + _ => FailureCode::Error0308, }, } } @@ -2809,36 +2808,51 @@ impl<'tcx> ObligationCause<'tcx> { span: Span, subdiags: Vec, ) -> ObligationCauseFailureCode { - use crate::traits::ObligationCauseCode::*; match self.code() { - CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => { ObligationCauseFailureCode::MethodCompat { span, subdiags } } - CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => { ObligationCauseFailureCode::TypeCompat { span, subdiags } } - CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { ObligationCauseFailureCode::ConstCompat { span, subdiags } } - BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => { + ObligationCauseCode::BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => { ObligationCauseFailureCode::TryCompat { span, subdiags } } - MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source { + ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { + source, .. + }) => match source { hir::MatchSource::TryDesugar(_) => { ObligationCauseFailureCode::TryCompat { span, subdiags } } _ => ObligationCauseFailureCode::MatchCompat { span, subdiags }, }, - IfExpression { .. } => ObligationCauseFailureCode::IfElseDifferent { span, subdiags }, - IfExpressionWithNoElse => ObligationCauseFailureCode::NoElse { span }, - LetElse => ObligationCauseFailureCode::NoDiverge { span, subdiags }, - MainFunctionType => ObligationCauseFailureCode::FnMainCorrectType { span }, - StartFunctionType => ObligationCauseFailureCode::FnStartCorrectType { span, subdiags }, - &LangFunctionType(lang_item_name) => { + ObligationCauseCode::IfExpression { .. } => { + ObligationCauseFailureCode::IfElseDifferent { span, subdiags } + } + ObligationCauseCode::IfExpressionWithNoElse => { + ObligationCauseFailureCode::NoElse { span } + } + ObligationCauseCode::LetElse => { + ObligationCauseFailureCode::NoDiverge { span, subdiags } + } + ObligationCauseCode::MainFunctionType => { + ObligationCauseFailureCode::FnMainCorrectType { span } + } + ObligationCauseCode::StartFunctionType => { + ObligationCauseFailureCode::FnStartCorrectType { span, subdiags } + } + &ObligationCauseCode::LangFunctionType(lang_item_name) => { ObligationCauseFailureCode::FnLangCorrectType { span, subdiags, lang_item_name } } - IntrinsicType => ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags }, - MethodReceiver => ObligationCauseFailureCode::MethodCorrectType { span, subdiags }, + ObligationCauseCode::IntrinsicType => { + ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags } + } + ObligationCauseCode::MethodReceiver => { + ObligationCauseFailureCode::MethodCorrectType { span, subdiags } + } // In the case where we have no more specific thing to // say, also take a look at the error code, maybe we can @@ -2858,22 +2872,21 @@ impl<'tcx> ObligationCause<'tcx> { } fn as_requirement_str(&self) -> &'static str { - use crate::traits::ObligationCauseCode::*; match self.code() { - CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => { "method type is compatible with trait" } - CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => { "associated type is compatible with trait" } - CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => { + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { "const is compatible with trait" } - MainFunctionType => "`main` function has the correct type", - StartFunctionType => "`#[start]` function has the correct type", - LangFunctionType(_) => "lang item function has the correct type", - IntrinsicType => "intrinsic has the correct type", - MethodReceiver => "method receiver has the correct type", + ObligationCauseCode::MainFunctionType => "`main` function has the correct type", + ObligationCauseCode::StartFunctionType => "`#[start]` function has the correct type", + ObligationCauseCode::LangFunctionType(_) => "lang item function has the correct type", + ObligationCauseCode::IntrinsicType => "intrinsic has the correct type", + ObligationCauseCode::MethodReceiver => "method receiver has the correct type", _ => "types are compatible", } } @@ -2884,16 +2897,17 @@ pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>); impl IntoDiagArg for ObligationCauseAsDiagArg<'_> { fn into_diag_arg(self) -> rustc_errors::DiagArgValue { - use crate::traits::ObligationCauseCode::*; let kind = match self.0.code() { - CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => "method_compat", - CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => "type_compat", - CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => "const_compat", - MainFunctionType => "fn_main_correct_type", - StartFunctionType => "fn_start_correct_type", - LangFunctionType(_) => "fn_lang_correct_type", - IntrinsicType => "intrinsic_correct_type", - MethodReceiver => "method_correct_type", + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => "method_compat", + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => "type_compat", + ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => { + "const_compat" + } + ObligationCauseCode::MainFunctionType => "fn_main_correct_type", + ObligationCauseCode::StartFunctionType => "fn_start_correct_type", + ObligationCauseCode::LangFunctionType(_) => "fn_lang_correct_type", + ObligationCauseCode::IntrinsicType => "intrinsic_correct_type", + ObligationCauseCode::MethodReceiver => "method_correct_type", _ => "other", } .into(); 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 a2a38d1c507a1..415f0eee8c510 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 @@ -3,7 +3,6 @@ use crate::errors::{ SourceKindMultiSuggestion, SourceKindSubdiag, }; use crate::infer::error_reporting::TypeErrCtxt; -use crate::infer::type_variable::TypeVariableOrigin; use crate::infer::InferCtxt; use rustc_errors::{codes::*, Diag, IntoDiagArg}; use rustc_hir as hir; @@ -13,7 +12,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource}; use rustc_middle::hir::nested_filter; -use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue}; +use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; use rustc_middle::ty::{ @@ -522,7 +521,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer_subdiags.push(SourceKindSubdiag::GenericLabel { span, is_type, - param_name: generics.params[argument_index].name.to_string(), + param_name: generics.own_params[argument_index].name.to_string(), parent_exists, parent_prefix, parent_name, @@ -542,18 +541,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { match arg.unpack() { GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), - GenericArgKind::Type(_) => self - .next_ty_var(TypeVariableOrigin { - span: DUMMY_SP, - param_def_id: None, - }) - .into(), - GenericArgKind::Const(arg) => self - .next_const_var( - arg.ty(), - ConstVariableOrigin { span: DUMMY_SP, param_def_id: None }, - ) - .into(), + GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(), + GenericArgKind::Const(arg) => { + self.next_const_var(arg.ty(), DUMMY_SP).into() + } } })) .unwrap(); @@ -569,9 +560,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } InferSourceKind::FullyQualifiedMethodCall { receiver, successor, args, def_id } => { - let placeholder = Some( - self.next_ty_var(TypeVariableOrigin { span: DUMMY_SP, param_def_id: None }), - ); + let placeholder = Some(self.next_ty_var(DUMMY_SP)); if let Some(args) = args.make_suggestable(self.infcx.tcx, true, placeholder) { let mut printer = fmt_printer(self, Namespace::ValueNS); printer.print_def_path(def_id, args).unwrap(); @@ -605,9 +594,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => { - let placeholder = Some( - self.next_ty_var(TypeVariableOrigin { span: DUMMY_SP, param_def_id: None }), - ); + let placeholder = Some(self.next_ty_var(DUMMY_SP)); if let Some(ty) = ty.make_suggestable(self.infcx.tcx, true, placeholder) { let ty_info = ty_to_string(self, ty, None); multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return( diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs index b93b8dc03f8a4..fdfce7f8f73c7 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs @@ -32,17 +32,20 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { // If we added a "points at argument expression" obligation, we remove it here, we care // about the original obligation only. let code = match cause.code() { - ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => &*parent_code, + ObligationCauseCode::FunctionArg { parent_code, .. } => &*parent_code, code => code, }; let ObligationCauseCode::MatchImpl(parent, impl_def_id) = code else { return None; }; - let (ObligationCauseCode::BindingObligation(_, binding_span) - | ObligationCauseCode::ExprBindingObligation(_, binding_span, ..)) = *parent.code() + let (ObligationCauseCode::WhereClause(_, binding_span) + | ObligationCauseCode::WhereClauseInExpr(_, binding_span, ..)) = *parent.code() else { return None; }; + if binding_span.is_dummy() { + return None; + } // FIXME: we should point at the lifetime let multi_span: MultiSpan = vec![binding_span].into(); 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 01e75d59f4dfe..31d45133eb0bc 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 @@ -10,9 +10,9 @@ use crate::traits::{ObligationCause, ObligationCauseCode}; use rustc_data_structures::intern::Interned; use rustc_errors::{Diag, IntoDiagArg}; use rustc_hir::def::Namespace; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; use rustc_middle::ty::error::ExpectedFound; -use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode}; +use rustc_middle::ty::print::{FmtPrinter, Print, PrintTraitRefExt as _, RegionHighlightMode}; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, RePlaceholder, Region, TyCtxt}; @@ -240,8 +240,9 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { let span = cause.span(); let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) = - if let ObligationCauseCode::ItemObligation(def_id) - | ObligationCauseCode::ExprItemObligation(def_id, ..) = *cause.code() + if let ObligationCauseCode::WhereClause(def_id, span) + | ObligationCauseCode::WhereClauseInExpr(def_id, span, ..) = *cause.code() + && def_id != CRATE_DEF_ID.to_def_id() { ( true, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 0bbabefaf9540..8a1e3a7ac71b7 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -214,8 +214,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { _ => cause.code(), } && let ( - &ObligationCauseCode::ItemObligation(item_def_id) - | &ObligationCauseCode::ExprItemObligation(item_def_id, ..), + &ObligationCauseCode::WhereClause(item_def_id, _) + | &ObligationCauseCode::WhereClauseInExpr(item_def_id, ..), None, ) = (code, override_error_code) { diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index b4cf727bf8f1a..7f3e23716f984 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -4,13 +4,13 @@ use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff} use crate::infer::error_reporting::nice_region_error::NiceRegionError; use crate::infer::lexical_region_resolve::RegionResolutionError; use crate::infer::{Subtype, ValuePairs}; -use crate::traits::ObligationCauseCode::CompareImplItemObligation; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; +use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::print::RegionHighlightMode; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor}; @@ -31,7 +31,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { _, ) = error.clone() && let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin) - && let CompareImplItemObligation { trait_item_def_id, .. } = sub_trace.cause.code() + && let ObligationCauseCode::CompareImplItem { trait_item_def_id, .. } = + sub_trace.cause.code() && sub_trace.values == sup_trace.values && let ValuePairs::PolySigs(ExpectedFound { expected, found }) = sub_trace.values { diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index 3ae1165d2a4da..00dd20a2cc270 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -357,21 +357,22 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { infer::Subtype(box ref trace) if matches!( &trace.cause.code().peel_derives(), - ObligationCauseCode::BindingObligation(..) - | ObligationCauseCode::ExprBindingObligation(..) + ObligationCauseCode::WhereClause(..) + | ObligationCauseCode::WhereClauseInExpr(..) ) => { // Hack to get around the borrow checker because trace.cause has an `Rc`. - if let ObligationCauseCode::BindingObligation(_, span) - | ObligationCauseCode::ExprBindingObligation(_, span, ..) = + if let ObligationCauseCode::WhereClause(_, span) + | ObligationCauseCode::WhereClauseInExpr(_, span, ..) = &trace.cause.code().peel_derives() + && !span.is_dummy() { let span = *span; self.report_concrete_failure(placeholder_origin, sub, sup) .with_span_note(span, "the lifetime requirement is introduced here") } else { unreachable!( - "control flow ensures we have a `BindingObligation` or `ExprBindingObligation` here..." + "control flow ensures we have a `BindingObligation` or `WhereClauseInExpr` here..." ) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 6a42f9b42c384..c24ad1fa1e73a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -629,8 +629,7 @@ impl Trait for X { | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }), ) ); - let impl_comparison = - matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. }); + let impl_comparison = matches!(cause_code, ObligationCauseCode::CompareImplItem { .. }); let assoc = tcx.associated_item(proj_ty.def_id); if impl_comparison { // We do not want to suggest calling functions when the reason of the diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index bf470bb1e3f89..75479decebcdf 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -167,7 +167,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { exp_span, exp_found.expected, exp_found.found, ); - if let ObligationCauseCode::CompareImplItemObligation { .. } = cause.code() { + if let ObligationCauseCode::CompareImplItem { .. } = cause.code() { return; } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index bb53aec0b4d13..ce82296a8aadd 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -528,8 +528,8 @@ pub enum RegionVariableOrigin { /// Region variables created as the values for early-bound regions. /// - /// FIXME(@lcnr): This can also store a `DefId`, similar to - /// `TypeVariableOriginKind::TypeParameterDefinition`. + /// FIXME(@lcnr): This should also store a `DefId`, similar to + /// `TypeVariableOrigin`. RegionParameterDefinition(Span, Symbol), /// Region variables created when instantiating a binder with @@ -989,72 +989,67 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow_mut().type_variables().num_vars() } - pub fn next_ty_var_id(&self, origin: TypeVariableOrigin) -> TyVid { - self.inner.borrow_mut().type_variables().new_var(self.universe(), origin) + pub fn next_ty_var(&self, span: Span) -> Ty<'tcx> { + self.next_ty_var_with_origin(TypeVariableOrigin { span, param_def_id: None }) } - pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - Ty::new_var(self.tcx, self.next_ty_var_id(origin)) + pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { + let vid = self.inner.borrow_mut().type_variables().new_var(self.universe(), origin); + Ty::new_var(self.tcx, vid) } - pub fn next_ty_var_id_in_universe( - &self, - origin: TypeVariableOrigin, - universe: ty::UniverseIndex, - ) -> TyVid { + pub fn next_ty_var_id_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> TyVid { + let origin = TypeVariableOrigin { span, param_def_id: None }; self.inner.borrow_mut().type_variables().new_var(universe, origin) } - pub fn next_ty_var_in_universe( - &self, - origin: TypeVariableOrigin, - universe: ty::UniverseIndex, - ) -> Ty<'tcx> { - let vid = self.next_ty_var_id_in_universe(origin, universe); + pub fn next_ty_var_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> Ty<'tcx> { + let vid = self.next_ty_var_id_in_universe(span, universe); Ty::new_var(self.tcx, vid) } - pub fn next_const_var(&self, ty: Ty<'tcx>, origin: ConstVariableOrigin) -> ty::Const<'tcx> { - ty::Const::new_var(self.tcx, self.next_const_var_id(origin), ty) + pub fn next_const_var(&self, ty: Ty<'tcx>, span: Span) -> ty::Const<'tcx> { + self.next_const_var_with_origin(ty, ConstVariableOrigin { span, param_def_id: None }) } - pub fn next_const_var_in_universe( + pub fn next_const_var_with_origin( &self, ty: Ty<'tcx>, origin: ConstVariableOrigin, - universe: ty::UniverseIndex, ) -> ty::Const<'tcx> { let vid = self .inner .borrow_mut() .const_unification_table() - .new_key(ConstVariableValue::Unknown { origin, universe }) + .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) .vid; ty::Const::new_var(self.tcx, vid, ty) } - pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid { - self.inner + pub fn next_const_var_in_universe( + &self, + ty: Ty<'tcx>, + span: Span, + universe: ty::UniverseIndex, + ) -> ty::Const<'tcx> { + let origin = ConstVariableOrigin { span, param_def_id: None }; + let vid = self + .inner .borrow_mut() .const_unification_table() - .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) - .vid - } - - fn next_int_var_id(&self) -> IntVid { - self.inner.borrow_mut().int_unification_table().new_key(None) + .new_key(ConstVariableValue::Unknown { origin, universe }) + .vid; + ty::Const::new_var(self.tcx, vid, ty) } pub fn next_int_var(&self) -> Ty<'tcx> { - Ty::new_int_var(self.tcx, self.next_int_var_id()) - } - - fn next_float_var_id(&self) -> FloatVid { - self.inner.borrow_mut().float_unification_table().new_key(None) + let vid = self.inner.borrow_mut().int_unification_table().new_key(None); + Ty::new_int_var(self.tcx, vid) } pub fn next_float_var(&self) -> Ty<'tcx> { - Ty::new_float_var(self.tcx, self.next_float_var_id()) + let vid = self.inner.borrow_mut().float_unification_table().new_key(None); + Ty::new_float_var(self.tcx, vid) } /// Creates a fresh region variable with the next available index. @@ -1468,24 +1463,13 @@ impl<'tcx> InferCtxt<'tcx> { fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> { self.map .entry(bt.var) - .or_insert_with(|| { - self.infcx - .next_ty_var(TypeVariableOrigin { param_def_id: None, span: self.span }) - .into() - }) + .or_insert_with(|| self.infcx.next_ty_var(self.span).into()) .expect_ty() } fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> { self.map .entry(bv) - .or_insert_with(|| { - self.infcx - .next_const_var( - ty, - ConstVariableOrigin { param_def_id: None, span: self.span }, - ) - .into() - }) + .or_insert_with(|| self.infcx.next_const_var(ty, self.span).into()) .expect_const() } } @@ -1892,7 +1876,7 @@ impl<'tcx> SubregionOrigin<'tcx> { SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span) } - traits::ObligationCauseCode::CompareImplItemObligation { + traits::ObligationCauseCode::CompareImplItem { impl_item_def_id, trait_item_def_id, kind: _, diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 94a546f87eee9..703bd5ae90b7d 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -1,4 +1,3 @@ -use super::type_variable::TypeVariableOrigin; use super::{DefineOpaqueTypes, InferResult}; use crate::errors::OpaqueHiddenTypeDiag; use crate::infer::{InferCtxt, InferOk}; @@ -65,7 +64,7 @@ impl<'tcx> InferCtxt<'tcx> { let span = if span.contains(def_span) { def_span } else { span }; let code = traits::ObligationCauseCode::OpaqueReturnType(None); let cause = ObligationCause::new(span, body_id, code); - let ty_var = self.next_ty_var(TypeVariableOrigin { param_def_id: None, span }); + let ty_var = self.next_ty_var(span); obligations.extend( self.handle_opaque_type(ty, ty_var, &cause, param_env).unwrap().obligations, ); @@ -485,6 +484,19 @@ impl<'tcx> InferCtxt<'tcx> { Ok(InferOk { value: (), obligations }) } + /// Insert a hidden type into the opaque type storage, making sure + /// it hasn't previously been defined. This does not emit any + /// constraints and it's the responsibility of the caller to make + /// sure that the item bounds of the opaque are checked. + pub fn inject_new_hidden_type_unchecked( + &self, + opaque_type_key: OpaqueTypeKey<'tcx>, + hidden_ty: OpaqueHiddenType<'tcx>, + ) { + let prev = self.inner.borrow_mut().opaque_types().register(opaque_type_key, hidden_ty); + assert_eq!(prev, None); + } + /// Insert a hidden type into the opaque type storage, equating it /// with any previous entries if necessary. /// diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index fe323982ec03c..e0d23d7629f99 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -103,8 +103,12 @@ impl<'tcx> InferCtxt<'tcx> { cause.span, sup_type, match cause.code().peel_derives() { - ObligationCauseCode::BindingObligation(_, span) - | ObligationCauseCode::ExprBindingObligation(_, span, ..) => Some(*span), + ObligationCauseCode::WhereClause(_, span) + | ObligationCauseCode::WhereClauseInExpr(_, span, ..) + if !span.is_dummy() => + { + Some(*span) + } _ => None, }, ) diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs index e60efe37fd9bc..041838ffc1693 100644 --- a/compiler/rustc_infer/src/infer/projection.rs +++ b/compiler/rustc_infer/src/infer/projection.rs @@ -3,7 +3,6 @@ use rustc_middle::ty::{self, Ty}; use crate::traits::{Obligation, PredicateObligation}; -use super::type_variable::TypeVariableOrigin; use super::InferCtxt; impl<'tcx> InferCtxt<'tcx> { @@ -23,10 +22,7 @@ impl<'tcx> InferCtxt<'tcx> { ) -> Ty<'tcx> { debug_assert!(!self.next_trait_solver()); let def_id = projection_ty.def_id; - let ty_var = self.next_ty_var(TypeVariableOrigin { - param_def_id: None, - span: self.tcx.def_span(def_id), - }); + let ty_var = self.next_ty_var(self.tcx.def_span(def_id)); let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Projection( ty::ProjectionPredicate { projection_ty, term: ty_var.into() }, ))); diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index 74929daffe247..5880ca788bce9 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -1,7 +1,7 @@ use std::mem; use super::StructurallyRelateAliases; -use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableValue}; +use crate::infer::type_variable::TypeVariableValue; use crate::infer::{InferCtxt, ObligationEmittingRelation, RegionVariableOrigin}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -350,11 +350,14 @@ impl<'tcx> Generalizer<'_, 'tcx> { &mut self, alias: ty::AliasTy<'tcx>, ) -> Result, TypeError<'tcx>> { - if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() { - return Ok(self.infcx.next_ty_var_in_universe( - TypeVariableOrigin { param_def_id: None, span: self.span }, - self.for_universe, - )); + // We do not eagerly replace aliases with inference variables if they have + // escaping bound vars, see the method comment for details. However, when we + // are inside of an alias with escaping bound vars replacing nested aliases + // with inference variables can cause incorrect ambiguity. + // + // cc trait-system-refactor-initiative#110 + if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias { + return Ok(self.infcx.next_ty_var_in_universe(self.span, self.for_universe)); } let is_nested_alias = mem::replace(&mut self.in_alias, true); @@ -374,10 +377,7 @@ impl<'tcx> Generalizer<'_, 'tcx> { } debug!("generalization failure in alias"); - Ok(self.infcx.next_ty_var_in_universe( - TypeVariableOrigin { param_def_id: None, span: self.span }, - self.for_universe, - )) + Ok(self.infcx.next_ty_var_in_universe(self.span, self.for_universe)) } } }; @@ -492,9 +492,30 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { let origin = inner.type_variables().var_origin(vid); let new_var_id = inner.type_variables().new_var(self.for_universe, origin); - let u = Ty::new_var(self.tcx(), new_var_id); - debug!("replacing original vid={:?} with new={:?}", vid, u); - Ok(u) + // If we're in the new solver and create a new inference + // variable inside of an alias we eagerly constrain that + // inference variable to prevent unexpected ambiguity errors. + // + // This is incomplete as it pulls down the universe of the + // original inference variable, even though the alias could + // normalize to a type which does not refer to that type at + // all. I don't expect this to cause unexpected errors in + // practice. + // + // We only need to do so for type and const variables, as + // region variables do not impact normalization, and will get + // correctly constrained by `AliasRelate` later on. + // + // cc trait-system-refactor-initiative#108 + if self.infcx.next_trait_solver() + && !self.infcx.intercrate + && self.in_alias + { + inner.type_variables().equate(vid, new_var_id); + } + + debug!("replacing original vid={:?} with new={:?}", vid, new_var_id); + Ok(Ty::new_var(self.tcx(), new_var_id)) } } } @@ -614,6 +635,15 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { universe: self.for_universe, }) .vid; + + // See the comment for type inference variables + // for more details. + if self.infcx.next_trait_solver() + && !self.infcx.intercrate + && self.in_alias + { + variable_table.union(vid, new_var_id); + } Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty())) } } diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index f9470c9b8f676..38e25b0d9b688 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -18,7 +18,6 @@ //! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order) use super::combine::ObligationEmittingRelation; -use crate::infer::type_variable::TypeVariableOrigin; use crate::infer::{DefineOpaqueTypes, InferCtxt}; use crate::traits::ObligationCause; @@ -88,14 +87,12 @@ where // iterate on the subtype obligations that are returned, but I // think this suffices. -nmatsakis (&ty::Infer(TyVar(..)), _) => { - let v = infcx - .next_ty_var(TypeVariableOrigin { param_def_id: None, span: this.cause().span }); + let v = infcx.next_ty_var(this.cause().span); this.relate_bound(v, b, a)?; Ok(v) } (_, &ty::Infer(TyVar(..))) => { - let v = infcx - .next_ty_var(TypeVariableOrigin { param_def_id: None, span: this.cause().span }); + let v = infcx.next_ty_var(this.cause().span); this.relate_bound(v, a, b)?; Ok(v) } diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index 83667f7276d48..4408251c99dc2 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -195,7 +195,7 @@ impl<'a, 'tcx> TypeFolder> for InferenceFudger<'a, 'tcx> { // Recreate it with a fresh variable here. let idx = vid.as_usize() - self.type_vars.0.start.as_usize(); let origin = self.type_vars.1[idx]; - self.infcx.next_ty_var(origin) + self.infcx.next_ty_var_with_origin(origin) } else { // This variable was created before the // "fudging". Since we refresh all type @@ -244,7 +244,7 @@ impl<'a, 'tcx> TypeFolder> for InferenceFudger<'a, 'tcx> { // Recreate it with a fresh variable here. let idx = vid.index() - self.const_vars.0.start.index(); let origin = self.const_vars.1[idx]; - self.infcx.next_const_var(ct.ty(), origin) + self.infcx.next_const_var_with_origin(ct.ty(), origin) } else { ct } diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index f77a611586180..85510cf2dcceb 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -105,7 +105,7 @@ impl<'tcx> PredicateObligation<'tcx> { impl<'tcx> PolyTraitObligation<'tcx> { pub fn derived_cause( &self, - variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, + variant: impl FnOnce(DerivedCause<'tcx>) -> ObligationCauseCode<'tcx>, ) -> ObligationCause<'tcx> { self.cause.clone().derived_cause(self.predicate, variant) } @@ -138,10 +138,10 @@ pub enum FulfillmentErrorCode<'tcx> { /// Inherently impossible to fulfill; this trait is implemented if and only /// if it is already implemented. Cycle(Vec>), - SelectionError(SelectionError<'tcx>), - ProjectionError(MismatchedProjectionTypes<'tcx>), - SubtypeError(ExpectedFound>, TypeError<'tcx>), // always comes from a SubtypePredicate - ConstEquateError(ExpectedFound>, TypeError<'tcx>), + Select(SelectionError<'tcx>), + Project(MismatchedProjectionTypes<'tcx>), + Subtype(ExpectedFound>, TypeError<'tcx>), // always comes from a SubtypePredicate + ConstEquate(ExpectedFound>, TypeError<'tcx>), Ambiguity { /// Overflow is only `Some(suggest_recursion_limit)` when using the next generation /// trait solver `-Znext-solver`. With the old solver overflow is eagerly handled by @@ -209,10 +209,10 @@ impl<'tcx> FulfillmentError<'tcx> { pub fn is_true_error(&self) -> bool { match self.code { - FulfillmentErrorCode::SelectionError(_) - | FulfillmentErrorCode::ProjectionError(_) - | FulfillmentErrorCode::SubtypeError(_, _) - | FulfillmentErrorCode::ConstEquateError(_, _) => true, + FulfillmentErrorCode::Select(_) + | FulfillmentErrorCode::Project(_) + | FulfillmentErrorCode::Subtype(_, _) + | FulfillmentErrorCode::ConstEquate(_, _) => true, FulfillmentErrorCode::Cycle(_) | FulfillmentErrorCode::Ambiguity { overflow: _ } => { false } diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index 064e09b875068..b616d37e5b5e3 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -39,12 +39,12 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use traits::FulfillmentErrorCode::*; match *self { - SelectionError(ref e) => write!(f, "{e:?}"), - ProjectionError(ref e) => write!(f, "{e:?}"), - SubtypeError(ref a, ref b) => { + Select(ref e) => write!(f, "{e:?}"), + Project(ref e) => write!(f, "{e:?}"), + Subtype(ref a, ref b) => { write!(f, "CodeSubtypeError({a:?}, {b:?})") } - ConstEquateError(ref a, ref b) => { + ConstEquate(ref a, ref b) => { write!(f, "CodeConstEquateError({a:?}, {b:?})") } Ambiguity { overflow: None } => write!(f, "Ambiguity"), diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 6d43011d33cad..d8d84b777e01a 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,7 +1,7 @@ use smallvec::smallvec; use crate::infer::outlives::components::{push_outlives_components, Component}; -use crate::traits::{self, Obligation, PredicateObligation}; +use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation}; use rustc_data_structures::fx::FxHashSet; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::Ident; @@ -129,7 +129,7 @@ impl<'tcx> Elaboratable<'tcx> for PredicateObligation<'tcx> { index: usize, ) -> Self { let cause = self.cause.clone().derived_cause(parent_trait_pred, |derived| { - traits::ImplDerivedObligation(Box::new(traits::ImplDerivedObligationCause { + ObligationCauseCode::ImplDerived(Box::new(traits::ImplDerivedCause { derived, impl_or_alias_def_id: parent_trait_pred.def_id(), impl_def_predicate_index: Some(index), diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 0e90836145efa..4b3b0728f385e 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -10,6 +10,7 @@ rustc-rayon-core = { version = "0.5.0", optional = true } rustc_ast = { path = "../rustc_ast" } rustc_ast_lowering = { path = "../rustc_ast_lowering" } rustc_ast_passes = { path = "../rustc_ast_passes" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr = { path = "../rustc_attr" } rustc_borrowck = { path = "../rustc_borrowck" } rustc_builtin_macros = { path = "../rustc_builtin_macros" } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index c5b81dbd67919..55304bbbd922f 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -120,14 +120,45 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec) -> CheckCfg { ); let filename = FileName::cfg_spec_source_code(&s); + const VISIT: &str = + "visit for more details"; + macro_rules! error { ($reason:expr) => { #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - dcx.fatal(format!( - concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"), - s - )) + { + let mut diag = + dcx.struct_fatal(format!("invalid `--check-cfg` argument: `{s}`")); + diag.note($reason); + diag.note(VISIT); + diag.emit() + } + }; + (in $arg:expr, $reason:expr) => { + #[allow(rustc::untranslatable_diagnostic)] + #[allow(rustc::diagnostic_outside_of_impl)] + { + let mut diag = + dcx.struct_fatal(format!("invalid `--check-cfg` argument: `{s}`")); + + let pparg = rustc_ast_pretty::pprust::meta_list_item_to_string($arg); + if let Some(lit) = $arg.lit() { + let (lit_kind_article, lit_kind_descr) = { + let lit_kind = lit.as_token_lit().kind; + (lit_kind.article(), lit_kind.descr()) + }; + diag.note(format!( + "`{pparg}` is {lit_kind_article} {lit_kind_descr} literal" + )); + } else { + diag.note(format!("`{pparg}` is invalid")); + } + + diag.note($reason); + diag.note(VISIT); + diag.emit() + } }; } @@ -183,7 +214,7 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec) -> CheckCfg { } any_specified = true; if !args.is_empty() { - error!("`any()` must be empty"); + error!(in arg, "`any()` takes no argument"); } } else if arg.has_name(sym::values) && let Some(args) = arg.meta_item_list() @@ -202,25 +233,25 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec) -> CheckCfg { && let Some(args) = arg.meta_item_list() { if values_any_specified { - error!("`any()` in `values()` cannot be specified multiple times"); + error!(in arg, "`any()` in `values()` cannot be specified multiple times"); } values_any_specified = true; if !args.is_empty() { - error!("`any()` must be empty"); + error!(in arg, "`any()` in `values()` takes no argument"); } } else if arg.has_name(sym::none) && let Some(args) = arg.meta_item_list() { values.insert(None); if !args.is_empty() { - error!("`none()` must be empty"); + error!(in arg, "`none()` in `values()` takes no argument"); } } else { - error!("`values()` arguments must be string literals, `none()` or `any()`"); + error!(in arg, "`values()` arguments must be string literals, `none()` or `any()`"); } } } else { - error!("`cfg()` arguments must be simple identifiers, `any()` or `values(...)`"); + error!(in arg, "`cfg()` arguments must be simple identifiers, `any()` or `values(...)`"); } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index ba316e5eeb041..b9be92b89afdf 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -40,6 +40,7 @@ use crate::{ }, EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext, }; +use ast::token::TokenKind; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast::{self as ast, *}; @@ -1869,16 +1870,24 @@ struct UnderMacro(bool); impl KeywordIdents { fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: &TokenStream) { + // Check if the preceding token is `$`, because we want to allow `$async`, etc. + let mut prev_dollar = false; for tt in tokens.trees() { match tt { // Only report non-raw idents. TokenTree::Token(token, _) => { if let Some((ident, token::IdentIsRaw::No)) = token.ident() { - self.check_ident_token(cx, UnderMacro(true), ident); + if !prev_dollar { + self.check_ident_token(cx, UnderMacro(true), ident); + } + } else if token.kind == TokenKind::Dollar { + prev_dollar = true; + continue; } } TokenTree::Delimited(.., tts) => self.check_tokens(cx, tts), } + prev_dollar = false; } } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 0931bb29963de..62ba9ef5c113a 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -30,7 +30,7 @@ use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_middle::bug; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; -use rustc_middle::ty::print::{with_no_trimmed_paths, PrintError}; +use rustc_middle::ty::print::{with_no_trimmed_paths, PrintError, PrintTraitRefExt as _}; use rustc_middle::ty::{self, print::Printer, GenericArg, RegisteredTools, Ty, TyCtxt}; use rustc_session::lint::{BuiltinLintDiag, LintExpectationId}; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs index ce3f45a17e9f6..a6876d8aae793 100644 --- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs +++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs @@ -9,7 +9,7 @@ use crate::{ use hir::{Expr, Pat}; use rustc_hir as hir; use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause}; -use rustc_middle::ty::{self, List}; +use rustc_middle::ty; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::ObligationCtxt; @@ -123,7 +123,7 @@ fn extract_iterator_next_call<'tcx>( fn suggest_question_mark<'tcx>( cx: &LateContext<'tcx>, adt: ty::AdtDef<'tcx>, - args: &List>, + args: ty::GenericArgsRef<'tcx>, span: Span, ) -> bool { let Some(body_id) = cx.enclosing_body else { return false }; @@ -150,11 +150,8 @@ fn suggest_question_mark<'tcx>( let ocx = ObligationCtxt::new(&infcx); let body_def_id = cx.tcx.hir().body_owner_def_id(body_id); - let cause = ObligationCause::new( - span, - body_def_id, - rustc_infer::traits::ObligationCauseCode::MiscObligation, - ); + let cause = + ObligationCause::new(span, body_def_id, rustc_infer::traits::ObligationCauseCode::Misc); ocx.register_bound( cause, diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 7bdf5ef6af406..885c0bb3a89cc 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -1,6 +1,5 @@ use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, TyKind}; use rustc_hir::{Path, QPath}; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_middle::ty::{self, Binder, Ty, TyCtxt, TypeFoldable, TypeFolder}; @@ -337,7 +336,7 @@ impl<'a, 'tcx, F: FnMut(DefId) -> bool> TypeFolder> if let Some(def) = t.ty_adt_def() && (self.did_has_local_parent)(def.did()) { - self.infcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span: self.infer_span }) + self.infcx.next_ty_var(self.infer_span) } else { t.super_fold_with(self) } diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 1ea1f496e508e..1d2e12ec575b3 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -1,9 +1,8 @@ use rustc_hir as hir; use rustc_infer::infer::TyCtxtInferExt; use rustc_macros::{LintDiagnostic, Subdiagnostic}; -use rustc_middle::ty::{ - self, fold::BottomUpFolder, print::TraitPredPrintModifiersAndPath, Ty, TypeFoldable, -}; +use rustc_middle::ty::print::{PrintTraitPredicateExt as _, TraitPredPrintModifiersAndPath}; +use rustc_middle::ty::{self, fold::BottomUpFolder, Ty, TypeFoldable}; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::{symbol::kw, Span}; use rustc_trait_selection::traits; diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs index 9fed91f72628e..34153e3a220d3 100644 --- a/compiler/rustc_lint/src/reference_casting.rs +++ b/compiler/rustc_lint/src/reference_casting.rs @@ -199,6 +199,16 @@ fn is_cast_to_bigger_memory_layout<'tcx>( let e_alloc = cx.expr_or_init(e); let e_alloc = if let ExprKind::AddrOf(_, _, inner_expr) = e_alloc.kind { inner_expr } else { e_alloc }; + + // if the current expr looks like this `&mut expr[index]` then just looking + // at `expr[index]` won't give us the underlying allocation, so we just skip it + // the same logic applies field access `&mut expr.field` and reborrows `&mut *expr`. + if let ExprKind::Index(..) | ExprKind::Field(..) | ExprKind::Unary(UnOp::Deref, ..) = + e_alloc.kind + { + return None; + } + let alloc_ty = cx.typeck_results().node_type(e_alloc.hir_id); // if we do not find it we bail out, as this may not be UB diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 4d372d612e90d..8866b2be07847 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -677,6 +677,33 @@ trait UnusedDelimLint { } // Check if LHS needs parens to prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }`. + // + // FIXME: https://github.com/rust-lang/rust/issues/119426 + // The syntax tree in this code is from after macro expansion, so the + // current implementation has both false negatives and false positives + // related to expressions containing macros. + // + // macro_rules! m1 { + // () => { + // 1 + // }; + // } + // + // fn f1() -> u8 { + // // Lint says parens are not needed, but they are. + // (m1! {} + 1) + // } + // + // macro_rules! m2 { + // () => { + // loop { break 1; } + // }; + // } + // + // fn f2() -> u8 { + // // Lint says parens are needed, but they are not. + // (m2!() + 1) + // } { let mut innermost = inner; loop { @@ -1501,7 +1528,7 @@ declare_lint_pass!(UnusedImportBraces => [UNUSED_IMPORT_BRACES]); impl UnusedImportBraces { fn check_use_tree(&self, cx: &EarlyContext<'_>, use_tree: &ast::UseTree, item: &ast::Item) { - if let ast::UseTreeKind::Nested(ref items) = use_tree.kind { + if let ast::UseTreeKind::Nested { ref items, .. } = use_tree.kind { // Recursively check nested UseTrees for (tree, _) in items { self.check_use_tree(cx, tree, item); @@ -1522,7 +1549,7 @@ impl UnusedImportBraces { rename.unwrap_or(orig_ident).name } ast::UseTreeKind::Glob => Symbol::intern("*"), - ast::UseTreeKind::Nested(_) => return, + ast::UseTreeKind::Nested { .. } => return, }; cx.emit_span_lint( diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index eea3ca44c48b2..5369454577249 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -38,7 +38,6 @@ declare_lint_pass! { DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, DEPRECATED_IN_FUTURE, DEPRECATED_WHERE_CLAUSE_LOCATION, - DEREFERENCING_MUT_BINDING, DUPLICATE_MACRO_ATTRIBUTES, ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, ELIDED_LIFETIMES_IN_PATHS, @@ -90,6 +89,7 @@ declare_lint_pass! { RUST_2021_INCOMPATIBLE_OR_PATTERNS, RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, RUST_2021_PRELUDE_COLLISIONS, + RUST_2024_INCOMPATIBLE_PAT, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, SINGLE_USE_LIFETIMES, SOFT_UNSTABLE, @@ -1630,34 +1630,34 @@ declare_lint! { } declare_lint! { - /// The `dereferencing_mut_binding` lint detects a `mut x` pattern that resets the binding mode, - /// as this behavior will change in rust 2024. + /// The `rust_2024_incompatible_pat` lint + /// detects patterns whose meaning will change in the Rust 2024 edition. /// /// ### Example /// - /// ```rust - /// # #![warn(dereferencing_mut_binding)] - /// let x = Some(123u32); - /// let _y = match &x { - /// Some(mut x) => { - /// x += 1; - /// x - /// } - /// None => 0, - /// }; + /// ```rust,edition2021 + /// #![feature(ref_pat_eat_one_layer_2024)] + /// #![warn(rust_2024_incompatible_pat)] + /// + /// if let Some(&a) = &Some(&0u8) { + /// let _: u8 = a; + /// } + /// if let Some(mut _a) = &mut Some(0u8) { + /// _a = 7u8; + /// } /// ``` /// /// {{produces}} /// /// ### Explanation /// - /// Without the `mut`, `x` would have type `&u32`. Pre-2024, adding `mut` makes `x` have type - /// `u32`, which was deemed surprising. After edition 2024, adding `mut` will not change the - /// type of `x`. This lint warns users of editions before 2024 to update their code. - pub DEREFERENCING_MUT_BINDING, + /// In Rust 2024 and above, the `mut` keyword does not reset the pattern binding mode, + /// and nor do `&` or `&mut` patterns. The lint will suggest code that + /// has the same meaning in all editions. + pub RUST_2024_INCOMPATIBLE_PAT, Allow, - "detects `mut x` bindings that change the type of `x`", - @feature_gate = sym::mut_preserve_binding_mode_2024; + "detects patterns whose meaning will change in Rust 2024", + @feature_gate = sym::ref_pat_eat_one_layer_2024; // FIXME uncomment below upon stabilization /*@future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index c206380a06ff3..83fda7ef07c49 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -10,5 +10,5 @@ libc = "0.2.73" [build-dependencies] # tidy-alphabetical-start -cc = "1.0.90" +cc = "1.0.97" # tidy-alphabetical-end diff --git a/compiler/rustc_macros/src/lift.rs b/compiler/rustc_macros/src/lift.rs index f7a84ba1510d0..d41ceb29816cc 100644 --- a/compiler/rustc_macros/src/lift.rs +++ b/compiler/rustc_macros/src/lift.rs @@ -41,7 +41,7 @@ pub fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStre s.add_impl_generic(newtcx); s.bound_impl( - quote!(::rustc_middle::ty::Lift<'__lifted>), + quote!(::rustc_middle::ty::Lift<::rustc_middle::ty::TyCtxt<'__lifted>>), quote! { type Lifted = #lifted; diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index c057f7e921e7f..7c96a6fa9a978 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1402,7 +1402,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let inferred_outlives = self.tcx.inferred_outlives_of(def_id); record_defaulted_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives); - for param in &g.params { + for param in &g.own_params { if let ty::GenericParamDefKind::Const { has_default: true, .. } = param.kind { let default = self.tcx.const_param_default(param.def_id); record!(self.tables.const_param_default[param.def_id] <- default); diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index f70ef51107f25..817ac5946276f 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -57,7 +57,7 @@ macro_rules! span_bug { macro_rules! TrivialLiftImpls { ($($ty:ty),+ $(,)?) => { $( - impl<'tcx> $crate::ty::Lift<'tcx> for $ty { + impl<'tcx> $crate::ty::Lift<$crate::ty::TyCtxt<'tcx>> for $ty { type Lifted = Self; fn lift_to_tcx(self, _: $crate::ty::TyCtxt<'tcx>) -> Option { Some(self) diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index ee3cdf36820de..38cb1d5f9a074 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -125,10 +125,11 @@ use std::io::{Read, Write}; use std::num::NonZero; use std::sync::atomic::{AtomicU32, Ordering}; +use smallvec::{smallvec, SmallVec}; + use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{HashMapExt, Lock}; -use rustc_data_structures::tiny_list::TinyList; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; @@ -266,8 +267,8 @@ type DecodingSessionId = NonZero; #[derive(Clone)] enum State { Empty, - InProgressNonAlloc(TinyList), - InProgress(TinyList, AllocId), + InProgressNonAlloc(SmallVec<[DecodingSessionId; 1]>), + InProgress(SmallVec<[DecodingSessionId; 1]>, AllocId), Done(AllocId), } @@ -337,8 +338,7 @@ impl<'s> AllocDecodingSession<'s> { // If this is an allocation, we need to reserve an // `AllocId` so we can decode cyclic graphs. let alloc_id = decoder.interner().reserve_alloc_id(); - *entry = - State::InProgress(TinyList::new_single(self.session_id), alloc_id); + *entry = State::InProgress(smallvec![self.session_id], alloc_id); Some(alloc_id) } AllocDiscriminant::Fn @@ -346,8 +346,7 @@ impl<'s> AllocDecodingSession<'s> { | AllocDiscriminant::VTable => { // Fns and statics cannot be cyclic, and their `AllocId` // is determined later by interning. - *entry = - State::InProgressNonAlloc(TinyList::new_single(self.session_id)); + *entry = State::InProgressNonAlloc(smallvec![self.session_id]); None } } @@ -357,7 +356,7 @@ impl<'s> AllocDecodingSession<'s> { bug!("this should be unreachable"); } else { // Start decoding concurrently. - sessions.insert(self.session_id); + sessions.push(self.session_id); None } } @@ -367,7 +366,7 @@ impl<'s> AllocDecodingSession<'s> { return alloc_id; } else { // Start decoding concurrently. - sessions.insert(self.session_id); + sessions.push(self.session_id); Some(alloc_id) } } diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index 3881723c5ec9c..4994679ad5dad 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -78,13 +78,9 @@ impl<'tcx> PlaceTy<'tcx> { } let answer = match *elem { ProjectionElem::Deref => { - let ty = self - .ty - .builtin_deref(true) - .unwrap_or_else(|| { - bug!("deref projection of non-dereferenceable ty {:?}", self) - }) - .ty; + let ty = self.ty.builtin_deref(true).unwrap_or_else(|| { + bug!("deref projection of non-dereferenceable ty {:?}", self) + }); PlaceTy::from_ty(ty) } ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => { diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index a7d8ead567738..c68b7a6c9eb39 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -682,6 +682,23 @@ impl<'tcx> Pat<'tcx> { true }) } + + /// Whether this a never pattern. + pub fn is_never_pattern(&self) -> bool { + let mut is_never_pattern = false; + self.walk(|pat| match &pat.kind { + PatKind::Never => { + is_never_pattern = true; + false + } + PatKind::Or { pats } => { + is_never_pattern = pats.iter().all(|p| p.is_never_pattern()); + false + } + _ => true, + }); + is_never_pattern + } } impl<'tcx> IntoDiagArg for Pat<'tcx> { diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 1ae037e09a75e..fb796bf87a1dd 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -33,8 +33,6 @@ use std::hash::{Hash, Hasher}; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; -pub use self::ObligationCauseCode::*; - /// Depending on the stage of compilation, we want projection to be /// more or less conservative. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable, Encodable, Decodable)] @@ -129,7 +127,7 @@ impl<'tcx> ObligationCause<'tcx> { } pub fn misc(span: Span, body_id: LocalDefId) -> ObligationCause<'tcx> { - ObligationCause::new(span, body_id, MiscObligation) + ObligationCause::new(span, body_id, ObligationCauseCode::Misc) } #[inline(always)] @@ -167,7 +165,7 @@ impl<'tcx> ObligationCause<'tcx> { pub fn derived_cause( mut self, parent_trait_pred: ty::PolyTraitPredicate<'tcx>, - variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, + variant: impl FnOnce(DerivedCause<'tcx>) -> ObligationCauseCode<'tcx>, ) -> ObligationCause<'tcx> { /*! * Creates a cause for obligations that are derived from @@ -182,15 +180,14 @@ impl<'tcx> ObligationCause<'tcx> { // NOTE(flaper87): As of now, it keeps track of the whole error // chain. Ideally, we should have a way to configure this either // by using -Z verbose-internals or just a CLI argument. - self.code = - variant(DerivedObligationCause { parent_trait_pred, parent_code: self.code }).into(); + self.code = variant(DerivedCause { parent_trait_pred, parent_code: self.code }).into(); self } pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> { match self.code() { - MatchImpl(cause, _) => cause.to_constraint_category(), - AscribeUserTypeProvePredicate(predicate_span) => { + ObligationCauseCode::MatchImpl(cause, _) => cause.to_constraint_category(), + ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span) => { ConstraintCategory::Predicate(*predicate_span) } _ => ConstraintCategory::BoringNoLocation, @@ -209,7 +206,7 @@ pub struct UnifyReceiverContext<'tcx> { #[derive(Clone, PartialEq, Eq, Default, HashStable)] #[derive(TypeVisitable, TypeFoldable, TyEncodable, TyDecodable)] pub struct InternedObligationCauseCode<'tcx> { - /// `None` for `ObligationCauseCode::MiscObligation` (a common case, occurs ~60% of + /// `None` for `ObligationCauseCode::Misc` (a common case, occurs ~60% of /// the time). `Some` otherwise. code: Option>>, } @@ -225,11 +222,7 @@ impl<'tcx> ObligationCauseCode<'tcx> { #[inline(always)] fn into(self) -> InternedObligationCauseCode<'tcx> { InternedObligationCauseCode { - code: if let ObligationCauseCode::MiscObligation = self { - None - } else { - Some(Lrc::new(self)) - }, + code: if let ObligationCauseCode::Misc = self { None } else { Some(Lrc::new(self)) }, } } } @@ -238,7 +231,7 @@ impl<'tcx> std::ops::Deref for InternedObligationCauseCode<'tcx> { type Target = ObligationCauseCode<'tcx>; fn deref(&self) -> &Self::Target { - self.code.as_deref().unwrap_or(&ObligationCauseCode::MiscObligation) + self.code.as_deref().unwrap_or(&ObligationCauseCode::Misc) } } @@ -246,7 +239,7 @@ impl<'tcx> std::ops::Deref for InternedObligationCauseCode<'tcx> { #[derive(TypeVisitable, TypeFoldable)] pub enum ObligationCauseCode<'tcx> { /// Not well classified or should be obvious from the span. - MiscObligation, + Misc, /// A slice or array is WF only if `T: Sized`. SliceOrArrayElem, @@ -254,22 +247,15 @@ pub enum ObligationCauseCode<'tcx> { /// A tuple is WF only if its middle elements are `Sized`. TupleElem, - /// Must satisfy all of the where-clause predicates of the - /// given item. - ItemObligation(DefId), - - /// Like `ItemObligation`, but carries the span of the - /// predicate when it can be identified. - BindingObligation(DefId, Span), - - /// Like `ItemObligation`, but carries the `HirId` of the - /// expression that caused the obligation, and the `usize` - /// indicates exactly which predicate it is in the list of - /// instantiated predicates. - ExprItemObligation(DefId, HirId, usize), + /// Represents a clause that comes from a specific item. + /// The span corresponds to the clause. + WhereClause(DefId, Span), - /// Combines `ExprItemObligation` and `BindingObligation`. - ExprBindingObligation(DefId, Span, HirId, usize), + /// Like `WhereClause`, but also identifies the expression + /// which requires the `where` clause to be proven, and also + /// identifies the index of the predicate in the `predicates_of` + /// list of the item. + WhereClauseInExpr(DefId, Span, HirId, usize), /// A type like `&'a T` is WF only if `T: 'a`. ReferenceOutlivesReferent(Ty<'tcx>), @@ -333,16 +319,18 @@ pub enum ObligationCauseCode<'tcx> { /// Derived obligation (i.e. theoretical `where` clause) on a built-in /// implementation like `Copy` or `Sized`. - BuiltinDerivedObligation(DerivedObligationCause<'tcx>), + BuiltinDerived(DerivedCause<'tcx>), /// Derived obligation (i.e. `where` clause) on an user-provided impl /// or a trait alias. - ImplDerivedObligation(Box>), + ImplDerived(Box>), /// Derived obligation for WF goals. - WellFormedDerivedObligation(DerivedObligationCause<'tcx>), + WellFormedDerived(DerivedCause<'tcx>), - FunctionArgumentObligation { + /// Derived obligation refined to point at a specific argument in + /// a call or method expression. + FunctionArg { /// The node of the relevant argument in the function call. arg_hir_id: HirId, /// The node of the function call. @@ -353,7 +341,7 @@ pub enum ObligationCauseCode<'tcx> { /// Error derived when checking an impl item is compatible with /// its corresponding trait item's definition - CompareImplItemObligation { + CompareImplItem { impl_item_def_id: LocalDefId, trait_item_def_id: DefId, kind: ty::AssocKind, @@ -432,8 +420,8 @@ pub enum ObligationCauseCode<'tcx> { /// then it will be used to perform HIR-based wf checking /// after an error occurs, in order to generate a more precise error span. /// This is purely for diagnostic purposes - it is always - /// correct to use `MiscObligation` instead, or to specify - /// `WellFormed(None)` + /// correct to use `Misc` instead, or to specify + /// `WellFormed(None)`. WellFormed(Option), /// From `match_impl`. The cause for us having to match an impl, and the DefId we are matching against. @@ -501,8 +489,8 @@ pub enum WellFormedLoc { #[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] #[derive(TypeVisitable, TypeFoldable)] -pub struct ImplDerivedObligationCause<'tcx> { - pub derived: DerivedObligationCause<'tcx>, +pub struct ImplDerivedCause<'tcx> { + pub derived: DerivedCause<'tcx>, /// The `DefId` of the `impl` that gave rise to the `derived` obligation. /// If the `derived` obligation arose from a trait alias, which conceptually has a synthetic impl, /// then this will be the `DefId` of that trait alias. Care should therefore be taken to handle @@ -540,10 +528,10 @@ impl<'tcx> ObligationCauseCode<'tcx> { pub fn parent(&self) -> Option<(&Self, Option>)> { match self { - FunctionArgumentObligation { parent_code, .. } => Some((parent_code, None)), - BuiltinDerivedObligation(derived) - | WellFormedDerivedObligation(derived) - | ImplDerivedObligation(box ImplDerivedObligationCause { derived, .. }) => { + ObligationCauseCode::FunctionArg { parent_code, .. } => Some((parent_code, None)), + ObligationCauseCode::BuiltinDerived(derived) + | ObligationCauseCode::WellFormedDerived(derived) + | ObligationCauseCode::ImplDerived(box ImplDerivedCause { derived, .. }) => { Some((&derived.parent_code, Some(derived.parent_trait_pred))) } _ => None, @@ -552,7 +540,7 @@ impl<'tcx> ObligationCauseCode<'tcx> { pub fn peel_match_impls(&self) -> &Self { match self { - MatchImpl(cause, _) => cause.code(), + ObligationCauseCode::MatchImpl(cause, _) => cause.code(), _ => self, } } @@ -598,7 +586,7 @@ pub struct IfExpressionCause<'tcx> { #[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] #[derive(TypeVisitable, TypeFoldable)] -pub struct DerivedObligationCause<'tcx> { +pub struct DerivedCause<'tcx> { /// The trait predicate of the parent obligation that led to the /// current obligation. Note that only trait obligations lead to /// derived obligations, so we just store the trait predicate here diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs index cddf9d5f874a3..2ddcb8aab2530 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect.rs @@ -123,6 +123,8 @@ pub enum ProbeStep<'tcx> { /// used whenever there are multiple candidates to prove the /// current goalby . NestedProbe(Probe<'tcx>), + /// A trait goal was satisfied by an impl candidate. + RecordImplArgs { impl_args: CanonicalState<'tcx, ty::GenericArgsRef<'tcx>> }, /// A call to `EvalCtxt::evaluate_added_goals_make_canonical_response` with /// `Certainty` was made. This is the certainty passed in, so it's not unified /// with the certainty of the `try_evaluate_added_goals` that is done within; diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_middle/src/traits/solve/inspect/format.rs index 11aa0e10931cb..e652f0586c4ea 100644 --- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs +++ b/compiler/rustc_middle/src/traits/solve/inspect/format.rs @@ -136,6 +136,9 @@ impl<'a, 'b> ProofTreeFormatter<'a, 'b> { ProbeStep::MakeCanonicalResponse { shallow_certainty } => { writeln!(this.f, "EVALUATE GOALS AND MAKE RESPONSE: {shallow_certainty:?}")? } + ProbeStep::RecordImplArgs { impl_args } => { + writeln!(this.f, "RECORDED IMPL ARGS: {impl_args:?}")? + } } } Ok(()) diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index a65b3a41ade3b..329d5f34a2123 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -8,7 +8,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_type_ir::ConstKind as IrConstKind; -use rustc_type_ir::{ConstTy, IntoKind, TypeFlags, WithCachedTypeInfo}; +use rustc_type_ir::{TypeFlags, WithCachedTypeInfo}; mod int; mod kind; @@ -30,7 +30,7 @@ rustc_data_structures::static_assert_size!(ConstKind<'_>, 32); #[rustc_pass_by_value] pub struct Const<'tcx>(pub(super) Interned<'tcx, WithCachedTypeInfo>>); -impl<'tcx> IntoKind for Const<'tcx> { +impl<'tcx> rustc_type_ir::inherent::IntoKind for Const<'tcx> { type Kind = ConstKind<'tcx>; fn kind(self) -> ConstKind<'tcx> { @@ -48,12 +48,6 @@ impl<'tcx> rustc_type_ir::visit::Flags for Const<'tcx> { } } -impl<'tcx> ConstTy> for Const<'tcx> { - fn ty(self) -> Ty<'tcx> { - self.ty() - } -} - /// Typed constant value. #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[derive(HashStable, TyEncodable, TyDecodable)] @@ -180,7 +174,7 @@ impl<'tcx> Const<'tcx> { } } -impl<'tcx> rustc_type_ir::new::Const> for Const<'tcx> { +impl<'tcx> rustc_type_ir::inherent::Const> for Const<'tcx> { fn new_anon_bound( tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, @@ -189,6 +183,10 @@ impl<'tcx> rustc_type_ir::new::Const> for Const<'tcx> { ) -> Self { Const::new_bound(tcx, debruijn, var, ty) } + + fn ty(self) -> Ty<'tcx> { + self.ty() + } } impl<'tcx> Const<'tcx> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index d2eacdf762f1b..f9d1a77c3d960 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -4,6 +4,8 @@ pub mod tls; +pub use rustc_type_ir::lift::Lift; + use crate::arena::Arena; use crate::dep_graph::{DepGraph, DepKindStruct}; use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarInfo, CanonicalVarInfos}; @@ -24,6 +26,7 @@ use crate::traits::solve; use crate::traits::solve::{ ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData, }; +use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, ConstData, GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern, @@ -97,17 +100,17 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type CanonicalVars = CanonicalVarInfos<'tcx>; type Ty = Ty<'tcx>; - type Pat = Pattern<'tcx>; type Tys = &'tcx List>; type AliasTy = ty::AliasTy<'tcx>; type ParamTy = ParamTy; type BoundTy = ty::BoundTy; type PlaceholderTy = ty::PlaceholderType; - type ErrorGuaranteed = ErrorGuaranteed; + type BoundExistentialPredicates = &'tcx List>; type PolyFnSig = PolyFnSig<'tcx>; type AllocId = crate::mir::interpret::AllocId; + type Pat = Pattern<'tcx>; type Const = ty::Const<'tcx>; type AliasConst = ty::UnevaluatedConst<'tcx>; @@ -119,8 +122,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type Region = Region<'tcx>; type EarlyParamRegion = ty::EarlyParamRegion; - type BoundRegion = ty::BoundRegion; type LateParamRegion = ty::LateParamRegion; + type BoundRegion = ty::BoundRegion; type InferRegion = ty::RegionVid; type PlaceholderRegion = ty::PlaceholderRegion; @@ -138,6 +141,27 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo]) -> Self::CanonicalVars { self.mk_canonical_var_infos(infos) } + + type GenericsOf = &'tcx ty::Generics; + fn generics_of(self, def_id: DefId) -> &'tcx ty::Generics { + self.generics_of(def_id) + } + + fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs { + self.mk_args(args) + } + + fn check_and_mk_args( + self, + def_id: DefId, + args: impl IntoIterator>>, + ) -> ty::GenericArgsRef<'tcx> { + self.check_and_mk_args(def_id, args) + } + + fn parent(self, def_id: Self::DefId) -> Self::DefId { + self.parent(def_id) + } } type InternedSet<'tcx, T> = ShardedHashMap, ()>; @@ -917,7 +941,7 @@ impl<'tcx> TyCtxt<'tcx> { ) } - pub fn lift>(self, value: T) -> Option { + pub fn lift>>(self, value: T) -> Option { value.lift_to_tcx(self) } @@ -1524,31 +1548,9 @@ impl<'tcx> TyCtxt<'tcx> { } } -/// A trait implemented for all `X<'a>` types that can be safely and -/// efficiently converted to `X<'tcx>` as long as they are part of the -/// provided `TyCtxt<'tcx>`. -/// This can be done, for example, for `Ty<'tcx>` or `GenericArgsRef<'tcx>` -/// by looking them up in their respective interners. -/// -/// However, this is still not the best implementation as it does -/// need to compare the components, even for interned values. -/// It would be more efficient if `TypedArena` provided a way to -/// determine whether the address is in the allocated range. -/// -/// `None` is returned if the value or one of the components is not part -/// of the provided context. -/// For `Ty`, `None` can be returned if either the type interner doesn't -/// contain the `TyKind` key or if the address of the interned -/// pointer differs. The latter case is possible if a primitive type, -/// e.g., `()` or `u8`, was interned in a different context. -pub trait Lift<'tcx>: fmt::Debug { - type Lifted: fmt::Debug + 'tcx; - fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option; -} - macro_rules! nop_lift { ($set:ident; $ty:ty => $lifted:ty) => { - impl<'a, 'tcx> Lift<'tcx> for $ty { + impl<'a, 'tcx> Lift> for $ty { type Lifted = $lifted; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { // Assert that the set has the right type. @@ -1583,7 +1585,7 @@ macro_rules! nop_lift { macro_rules! nop_list_lift { ($set:ident; $ty:ty => $lifted:ty) => { - impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> { + impl<'a, 'tcx> Lift> for &'a List<$ty> { type Lifted = &'tcx List<$lifted>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { // Assert that the set has the right type. @@ -1621,7 +1623,7 @@ nop_list_lift! {args; GenericArg<'a> => GenericArg<'tcx>} macro_rules! nop_slice_lift { ($ty:ty => $lifted:ty) => { - impl<'a, 'tcx> Lift<'tcx> for &'a [$ty] { + impl<'a, 'tcx> Lift> for &'a [$ty] { type Lifted = &'tcx [$lifted]; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { if self.is_empty() { @@ -2060,7 +2062,7 @@ impl<'tcx> TyCtxt<'tcx> { && let DefKind::AssocTy = self.def_kind(def_id) && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id)) { - if generics.params.len() + 1 != args.len() { + if generics.own_params.len() + 1 != args.len() { return false; } @@ -2085,7 +2087,7 @@ impl<'tcx> TyCtxt<'tcx> { own_args }; - for (param, arg) in std::iter::zip(&generics.params, own_args) { + for (param, arg) in std::iter::zip(&generics.own_params, own_args) { match (¶m.kind, arg.unpack()) { (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_)) | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_)) @@ -2331,7 +2333,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn mk_args_from_iter(self, iter: I) -> T::Output where I: Iterator, - T: CollectAndApply, &'tcx List>>, + T: CollectAndApply, ty::GenericArgsRef<'tcx>>, { T::collect_and_apply(iter, |xs| self.mk_args(xs)) } @@ -2449,7 +2451,7 @@ impl<'tcx> TyCtxt<'tcx> { span, msg, format!("#![feature({feature})]\n"), - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, ); } else { diag.help(msg); diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index de2c01c304612..904c0c332a858 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -39,6 +39,16 @@ pub struct GenericArg<'tcx> { marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>, } +impl<'tcx> rustc_type_ir::inherent::GenericArgs> for ty::GenericArgsRef<'tcx> { + fn type_at(self, i: usize) -> Ty<'tcx> { + self.type_at(i) + } + + fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::GenericArgsRef<'tcx> { + GenericArgs::identity_for_item(tcx, def_id) + } +} + #[cfg(parallel_compiler)] unsafe impl<'tcx> rustc_data_structures::sync::DynSend for GenericArg<'tcx> where &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): rustc_data_structures::sync::DynSend @@ -205,7 +215,7 @@ impl<'tcx> GenericArg<'tcx> { } } -impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> { +impl<'a, 'tcx> Lift> for GenericArg<'a> { type Lifted = GenericArg<'tcx>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { @@ -359,8 +369,8 @@ impl<'tcx> GenericArgs<'tcx> { ) where F: FnMut(&ty::GenericParamDef, &[GenericArg<'tcx>]) -> GenericArg<'tcx>, { - args.reserve(defs.params.len()); - for param in &defs.params { + args.reserve(defs.own_params.len()); + for param in &defs.own_params { let kind = mk_kind(param, args); assert_eq!(param.index as usize, args.len(), "{args:#?}, {defs:#?}"); args.push(kind); diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 6bf2051d67ccd..04655c5d20bad 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -132,7 +132,7 @@ pub struct GenericParamCount { pub struct Generics { pub parent: Option, pub parent_count: usize, - pub params: Vec, + pub own_params: Vec, /// Reverse map to the `index` field of each `GenericParamDef`. #[stable_hasher(ignore)] @@ -145,6 +145,12 @@ pub struct Generics { pub host_effect_index: Option, } +impl<'tcx> rustc_type_ir::inherent::GenericsOf> for &'tcx Generics { + fn count(&self) -> usize { + self.parent_count + self.own_params.len() + } +} + impl<'tcx> Generics { /// Looks through the generics and all parents to find the index of the /// given param def-id. This is in comparison to the `param_def_id_to_index` @@ -163,7 +169,7 @@ impl<'tcx> Generics { #[inline] pub fn count(&self) -> usize { - self.parent_count + self.params.len() + self.parent_count + self.own_params.len() } pub fn own_counts(&self) -> GenericParamCount { @@ -172,7 +178,7 @@ impl<'tcx> Generics { // presence of this method will be a constant reminder. let mut own_counts = GenericParamCount::default(); - for param in &self.params { + for param in &self.own_params { match param.kind { GenericParamDefKind::Lifetime => own_counts.lifetimes += 1, GenericParamDefKind::Type { .. } => own_counts.types += 1, @@ -186,7 +192,7 @@ impl<'tcx> Generics { pub fn own_defaults(&self) -> GenericParamCount { let mut own_defaults = GenericParamCount::default(); - for param in &self.params { + for param in &self.own_params { match param.kind { GenericParamDefKind::Lifetime => (), GenericParamDefKind::Type { has_default, .. } => { @@ -215,7 +221,7 @@ impl<'tcx> Generics { } pub fn own_requires_monomorphization(&self) -> bool { - for param in &self.params { + for param in &self.own_params { match param.kind { GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { is_host_effect: false, .. } => { @@ -231,7 +237,7 @@ impl<'tcx> Generics { /// Returns the `GenericParamDef` with the given index. pub fn param_at(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef { if let Some(index) = param_index.checked_sub(self.parent_count) { - &self.params[index] + &self.own_params[index] } else { tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?")) .param_at(param_index, tcx) @@ -245,7 +251,7 @@ impl<'tcx> Generics { tcx: TyCtxt<'tcx>, ) -> Option<&'tcx GenericParamDef> { if let Some(index) = param_index.checked_sub(self.parent_count) { - self.params.get(index) + self.own_params.get(index) } else { tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?")) .opt_param_at(param_index, tcx) @@ -254,7 +260,7 @@ impl<'tcx> Generics { pub fn params_to(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx [GenericParamDef] { if let Some(index) = param_index.checked_sub(self.parent_count) { - &self.params[..index] + &self.own_params[..index] } else { tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?")) .params_to(param_index, tcx) @@ -308,7 +314,7 @@ impl<'tcx> Generics { /// Returns `true` if `params` has `impl Trait`. pub fn has_impl_trait(&'tcx self) -> bool { - self.params.iter().any(|param| { + self.own_params.iter().any(|param| { matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. }) }) } @@ -336,7 +342,7 @@ impl<'tcx> Generics { // good enough for now as this should only be used // for diagnostics anyways. own_params.end -= self - .params + .own_params .iter() .rev() .take_while(|param| { @@ -358,7 +364,7 @@ impl<'tcx> Generics { &'tcx self, args: &'tcx [ty::GenericArg<'tcx>], ) -> &'tcx [ty::GenericArg<'tcx>] { - let own = &args[self.parent_count..][..self.params.len()]; + let own = &args[self.parent_count..][..self.own_params.len()]; if self.has_self && self.parent.is_none() { &own[1..] } else { own } } @@ -372,7 +378,7 @@ impl<'tcx> Generics { args: &'tcx [ty::GenericArg<'tcx>], ) -> bool { let mut default_param_seen = false; - for param in self.params.iter() { + for param in self.own_params.iter() { if let Some(inst) = param.default_value(tcx).map(|default| default.instantiate(tcx, args)) { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index f8490e5e15fc0..cf701f837d895 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -114,16 +114,35 @@ impl Integer { } } -#[extension(pub trait PrimitiveExt)] -impl Primitive { +#[extension(pub trait FloatExt)] +impl Float { #[inline] fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { match *self { - Int(i, signed) => i.to_ty(tcx, signed), F16 => tcx.types.f16, F32 => tcx.types.f32, F64 => tcx.types.f64, F128 => tcx.types.f128, + } + } + + fn from_float_ty(fty: ty::FloatTy) -> Self { + match fty { + ty::FloatTy::F16 => F16, + ty::FloatTy::F32 => F32, + ty::FloatTy::F64 => F64, + ty::FloatTy::F128 => F128, + } + } +} + +#[extension(pub trait PrimitiveExt)] +impl Primitive { + #[inline] + fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { + match *self { + Int(i, signed) => i.to_ty(tcx, signed), + Float(f) => f.to_ty(tcx), // FIXME(erikdesjardins): handle non-default addrspace ptr sizes Pointer(_) => Ty::new_mut_ptr(tcx, tcx.types.unit), } @@ -140,7 +159,7 @@ impl Primitive { let signed = false; tcx.data_layout().ptr_sized_integer().to_ty(tcx, signed) } - F16 | F32 | F64 | F128 => bug!("floats do not have an int type"), + Float(_) => bug!("floats do not have an int type"), } } } @@ -333,7 +352,23 @@ impl<'tcx> SizeSkeleton<'tcx> { match *ty.kind() { ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => { let non_zero = !ty.is_unsafe_ptr(); - let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env); + + let tail = tcx.struct_tail_with_normalize( + pointee, + |ty| match tcx.try_normalize_erasing_regions(param_env, ty) { + Ok(ty) => ty, + Err(e) => Ty::new_error_with_message( + tcx, + DUMMY_SP, + format!( + "normalization failed for {} but no errors reported", + e.get_type_for_failure() + ), + ), + }, + || {}, + ); + match tail.kind() { ty::Param(_) | ty::Alias(ty::Projection | ty::Inherent, _) => { debug_assert!(tail.has_non_region_param()); diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 73b20f0485b6e..4d3b92bf2affd 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -96,13 +96,13 @@ 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, - PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef, - PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate, - PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate, - RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitPredicate, - TraitRef, TypeOutlivesPredicate, + Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialPredicateStableCmpExt, + ExistentialProjection, ExistentialTraitRef, NormalizesTo, OutlivesPredicate, + PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection, + PolyExistentialTraitRef, PolyProjectionPredicate, PolyRegionOutlivesPredicate, + PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, + PredicateKind, ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, + ToPredicate, TraitPredicate, TraitRef, TypeOutlivesPredicate, }; pub use self::region::{ BoundRegion, BoundRegionKind, BoundRegionKind::*, EarlyParamRegion, LateParamRegion, Region, @@ -275,61 +275,6 @@ pub enum ImplSubject<'tcx> { Inherent(Ty<'tcx>), } -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)] -#[derive(TypeFoldable, TypeVisitable)] -pub enum ImplPolarity { - /// `impl Trait for Type` - Positive, - /// `impl !Trait for Type` - Negative, - /// `#[rustc_reservation_impl] impl Trait for Type` - /// - /// This is a "stability hack", not a real Rust feature. - /// See #64631 for details. - Reservation, -} - -impl fmt::Display for ImplPolarity { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Positive => f.write_str("positive"), - Self::Negative => f.write_str("negative"), - Self::Reservation => f.write_str("reservation"), - } - } -} - -/// Polarity for a trait predicate. May either be negative or positive. -/// Distinguished from [`ImplPolarity`] since we never compute goals with -/// "reservation" level. -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)] -#[derive(TypeFoldable, TypeVisitable)] -pub enum PredicatePolarity { - /// `Type: Trait` - Positive, - /// `Type: !Trait` - Negative, -} - -impl PredicatePolarity { - /// Flips polarity by turning `Positive` into `Negative` and `Negative` into `Positive`. - pub fn flip(&self) -> PredicatePolarity { - match self { - PredicatePolarity::Positive => PredicatePolarity::Negative, - PredicatePolarity::Negative => PredicatePolarity::Positive, - } - } -} - -impl fmt::Display for PredicatePolarity { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Positive => f.write_str("positive"), - Self::Negative => f.write_str("negative"), - } - } -} - #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)] #[derive(TypeFoldable, TypeVisitable)] pub enum Asyncness { @@ -530,7 +475,7 @@ pub struct CReaderCacheKey { #[rustc_pass_by_value] pub struct Ty<'tcx>(Interned<'tcx, WithCachedTypeInfo>>); -impl<'tcx> IntoKind for Ty<'tcx> { +impl<'tcx> rustc_type_ir::inherent::IntoKind for Ty<'tcx> { type Kind = TyKind<'tcx>; fn kind(self) -> TyKind<'tcx> { @@ -981,7 +926,7 @@ pub struct Placeholder { pub type PlaceholderRegion = Placeholder; -impl PlaceholderLike for PlaceholderRegion { +impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderRegion { fn universe(self) -> UniverseIndex { self.universe } @@ -1001,7 +946,7 @@ impl PlaceholderLike for PlaceholderRegion { pub type PlaceholderType = Placeholder; -impl PlaceholderLike for PlaceholderType { +impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderType { fn universe(self) -> UniverseIndex { self.universe } @@ -1028,7 +973,7 @@ pub struct BoundConst<'tcx> { pub type PlaceholderConst = Placeholder; -impl PlaceholderLike for PlaceholderConst { +impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderConst { fn universe(self) -> UniverseIndex { self.universe } diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 791f27a97896d..115cf3eeb226c 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -100,8 +100,7 @@ impl<'tcx> TyCtxt<'tcx> { /// codegen, we need to normalize the contents. // FIXME(@lcnr): This method should not be necessary, we now normalize // inside of binders. We should be able to only use - // `tcx.instantiate_bound_regions_with_erased`. Same for the `try_X` - // variant. + // `tcx.instantiate_bound_regions_with_erased`. #[tracing::instrument(level = "debug", skip(self, param_env))] pub fn normalize_erasing_late_bound_regions( self, @@ -115,26 +114,6 @@ impl<'tcx> TyCtxt<'tcx> { self.normalize_erasing_regions(param_env, value) } - /// If you have a `Binder<'tcx, T>`, you can do this to strip out the - /// late-bound regions and then normalize the result, yielding up - /// a `T` (with regions erased). This is appropriate when the - /// binder is being instantiated at the call site. - /// - /// N.B., currently, higher-ranked type bounds inhibit - /// normalization. Therefore, each time we erase them in - /// codegen, we need to normalize the contents. - pub fn try_normalize_erasing_late_bound_regions( - self, - param_env: ty::ParamEnv<'tcx>, - value: ty::Binder<'tcx, T>, - ) -> Result> - where - T: TypeFoldable>, - { - let value = self.instantiate_bound_regions_with_erased(value); - self.try_normalize_erasing_regions(param_env, value) - } - /// Monomorphizes a type from the AST by first applying the /// in-scope instantiations and then normalizing any associated /// types. diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 56dd52567fde0..c1de23b249864 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -1,22 +1,28 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::Interned; -use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_hir::def_id::DefId; -use rustc_hir::LangItem; -use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; -use rustc_span::Span; -use rustc_type_ir::ClauseKind as IrClauseKind; -use rustc_type_ir::PredicateKind as IrPredicateKind; +use rustc_macros::{ + extension, HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, +}; +use rustc_type_ir as ir; use std::cmp::Ordering; -use crate::ty::visit::TypeVisitableExt; use crate::ty::{ - self, AliasTy, Binder, DebruijnIndex, DebugWithInfcx, EarlyBinder, GenericArg, GenericArgs, - GenericArgsRef, PredicatePolarity, Term, Ty, TyCtxt, TypeFlags, WithCachedTypeInfo, + self, Binder, DebruijnIndex, EarlyBinder, PredicatePolarity, Term, Ty, TyCtxt, TypeFlags, + WithCachedTypeInfo, }; -pub type ClauseKind<'tcx> = IrClauseKind>; -pub type PredicateKind<'tcx> = IrPredicateKind>; +pub type TraitRef<'tcx> = ir::TraitRef>; +pub type ProjectionPredicate<'tcx> = ir::ProjectionPredicate>; +pub type ExistentialPredicate<'tcx> = ir::ExistentialPredicate>; +pub type ExistentialTraitRef<'tcx> = ir::ExistentialTraitRef>; +pub type ExistentialProjection<'tcx> = ir::ExistentialProjection>; +pub type TraitPredicate<'tcx> = ir::TraitPredicate>; +pub type ClauseKind<'tcx> = ir::ClauseKind>; +pub type PredicateKind<'tcx> = ir::PredicateKind>; +pub type NormalizesTo<'tcx> = ir::NormalizesTo>; +pub type CoercePredicate<'tcx> = ir::CoercePredicate>; +pub type SubtypePredicate<'tcx> = ir::SubtypePredicate>; /// A statement that can be proven by a trait solver. This includes things that may /// show up in where clauses, such as trait predicates and projection predicates, @@ -30,6 +36,8 @@ pub struct Predicate<'tcx>( pub(super) Interned<'tcx, WithCachedTypeInfo>>>, ); +impl<'tcx> rustc_type_ir::inherent::Predicate> for Predicate<'tcx> {} + impl<'tcx> rustc_type_ir::visit::Flags for Predicate<'tcx> { fn flags(&self) -> TypeFlags { self.0.flags @@ -193,43 +201,25 @@ impl<'tcx> Clause<'tcx> { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub enum ExistentialPredicate<'tcx> { - /// E.g., `Iterator`. - Trait(ExistentialTraitRef<'tcx>), - /// E.g., `Iterator::Item = T`. - Projection(ExistentialProjection<'tcx>), - /// E.g., `Send`. - AutoTrait(DefId), -} - -impl<'tcx> DebugWithInfcx> for ExistentialPredicate<'tcx> { - fn fmt>>( - this: rustc_type_ir::WithInfcx<'_, Infcx, &Self>, - f: &mut std::fmt::Formatter<'_>, - ) -> std::fmt::Result { - std::fmt::Debug::fmt(&this.data, f) - } -} - +#[extension(pub trait ExistentialPredicateStableCmpExt<'tcx>)] impl<'tcx> ExistentialPredicate<'tcx> { /// Compares via an ordering that will not change if modules are reordered or other changes are /// made to the tree. In particular, this ordering is preserved across incremental compilations. - pub fn stable_cmp(&self, tcx: TyCtxt<'tcx>, other: &Self) -> Ordering { - use self::ExistentialPredicate::*; + fn stable_cmp(&self, tcx: TyCtxt<'tcx>, other: &Self) -> Ordering { match (*self, *other) { - (Trait(_), Trait(_)) => Ordering::Equal, - (Projection(ref a), Projection(ref b)) => { + (ExistentialPredicate::Trait(_), ExistentialPredicate::Trait(_)) => Ordering::Equal, + (ExistentialPredicate::Projection(ref a), ExistentialPredicate::Projection(ref b)) => { tcx.def_path_hash(a.def_id).cmp(&tcx.def_path_hash(b.def_id)) } - (AutoTrait(ref a), AutoTrait(ref b)) => { + (ExistentialPredicate::AutoTrait(ref a), ExistentialPredicate::AutoTrait(ref b)) => { tcx.def_path_hash(*a).cmp(&tcx.def_path_hash(*b)) } - (Trait(_), _) => Ordering::Less, - (Projection(_), Trait(_)) => Ordering::Greater, - (Projection(_), _) => Ordering::Less, - (AutoTrait(_), _) => Ordering::Greater, + (ExistentialPredicate::Trait(_), _) => Ordering::Less, + (ExistentialPredicate::Projection(_), ExistentialPredicate::Trait(_)) => { + Ordering::Greater + } + (ExistentialPredicate::Projection(_), _) => Ordering::Less, + (ExistentialPredicate::AutoTrait(_), _) => Ordering::Greater, } } } @@ -250,7 +240,7 @@ impl<'tcx> PolyExistentialPredicate<'tcx> { } ExistentialPredicate::AutoTrait(did) => { let generics = tcx.generics_of(did); - let trait_ref = if generics.params.len() == 1 { + let trait_ref = if generics.own_params.len() == 1 { ty::TraitRef::new(tcx, did, [self_ty]) } else { // If this is an ill-formed auto trait, then synthesize @@ -326,76 +316,6 @@ impl<'tcx> ty::List> { } } -/// A complete reference to a trait. These take numerous guises in syntax, -/// but perhaps the most recognizable form is in a where-clause: -/// ```ignore (illustrative) -/// T: Foo -/// ``` -/// This would be represented by a trait-reference where the `DefId` is the -/// `DefId` for the trait `Foo` and the args define `T` as parameter 0, -/// and `U` as parameter 1. -/// -/// Trait references also appear in object types like `Foo`, but in -/// that case the `Self` parameter is absent from the generic parameters. -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct TraitRef<'tcx> { - pub def_id: DefId, - pub args: GenericArgsRef<'tcx>, - /// This field exists to prevent the creation of `TraitRef` without - /// calling [`TraitRef::new`]. - pub(super) _use_trait_ref_new_instead: (), -} - -impl<'tcx> TraitRef<'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - args: impl IntoIterator>>, - ) -> Self { - let args = tcx.check_and_mk_args(trait_def_id, args); - Self { def_id: trait_def_id, args, _use_trait_ref_new_instead: () } - } - - pub fn from_lang_item( - tcx: TyCtxt<'tcx>, - trait_lang_item: LangItem, - span: Span, - args: impl IntoIterator>>, - ) -> Self { - let trait_def_id = tcx.require_lang_item(trait_lang_item, Some(span)); - Self::new(tcx, trait_def_id, args) - } - - pub fn from_method( - tcx: TyCtxt<'tcx>, - trait_id: DefId, - args: GenericArgsRef<'tcx>, - ) -> ty::TraitRef<'tcx> { - let defs = tcx.generics_of(trait_id); - ty::TraitRef::new(tcx, trait_id, tcx.mk_args(&args[..defs.params.len()])) - } - - /// Returns a `TraitRef` of the form `P0: Foo` where `Pi` - /// are the parameters defined on trait. - pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> TraitRef<'tcx> { - ty::TraitRef::new(tcx, def_id, GenericArgs::identity_for_item(tcx, def_id)) - } - - pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { - ty::TraitRef::new( - tcx, - self.def_id, - [self_ty.into()].into_iter().chain(self.args.iter().skip(1)), - ) - } - - #[inline] - pub fn self_ty(&self) -> Ty<'tcx> { - self.args.type_at(0) - } -} - pub type PolyTraitRef<'tcx> = ty::Binder<'tcx, TraitRef<'tcx>>; impl<'tcx> PolyTraitRef<'tcx> { @@ -408,58 +328,6 @@ impl<'tcx> PolyTraitRef<'tcx> { } } -impl<'tcx> IntoDiagArg for TraitRef<'tcx> { - fn into_diag_arg(self) -> DiagArgValue { - self.to_string().into_diag_arg() - } -} - -/// An existential reference to a trait, where `Self` is erased. -/// For example, the trait object `Trait<'a, 'b, X, Y>` is: -/// ```ignore (illustrative) -/// exists T. T: Trait<'a, 'b, X, Y> -/// ``` -/// The generic parameters don't include the erased `Self`, only trait -/// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above). -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct ExistentialTraitRef<'tcx> { - pub def_id: DefId, - pub args: GenericArgsRef<'tcx>, -} - -impl<'tcx> ExistentialTraitRef<'tcx> { - pub fn erase_self_ty( - tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - ) -> ty::ExistentialTraitRef<'tcx> { - // Assert there is a Self. - trait_ref.args.type_at(0); - - ty::ExistentialTraitRef { - def_id: trait_ref.def_id, - args: tcx.mk_args(&trait_ref.args[1..]), - } - } - - /// Object types don't have a self type specified. Therefore, when - /// we convert the principal trait-ref into a normal trait-ref, - /// you must give *some* self type. A common choice is `mk_err()` - /// or some placeholder type. - pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::TraitRef<'tcx> { - // otherwise the escaping vars would be captured by the binder - // debug_assert!(!self_ty.has_escaping_bound_vars()); - - ty::TraitRef::new(tcx, self.def_id, [self_ty.into()].into_iter().chain(self.args.iter())) - } -} - -impl<'tcx> IntoDiagArg for ExistentialTraitRef<'tcx> { - fn into_diag_arg(self) -> DiagArgValue { - self.to_string().into_diag_arg() - } -} - pub type PolyExistentialTraitRef<'tcx> = ty::Binder<'tcx, ExistentialTraitRef<'tcx>>; impl<'tcx> PolyExistentialTraitRef<'tcx> { @@ -476,62 +344,8 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { } } -/// A `ProjectionPredicate` for an `ExistentialTraitRef`. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct ExistentialProjection<'tcx> { - pub def_id: DefId, - pub args: GenericArgsRef<'tcx>, - pub term: Term<'tcx>, -} - pub type PolyExistentialProjection<'tcx> = ty::Binder<'tcx, ExistentialProjection<'tcx>>; -impl<'tcx> ExistentialProjection<'tcx> { - /// Extracts the underlying existential trait reference from this projection. - /// For example, if this is a projection of `exists T. ::Item == X`, - /// then this function would return an `exists T. T: Iterator` existential trait - /// reference. - pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> { - let def_id = tcx.parent(self.def_id); - let args_count = tcx.generics_of(def_id).count() - 1; - let args = tcx.mk_args(&self.args[..args_count]); - ty::ExistentialTraitRef { def_id, args } - } - - pub fn with_self_ty( - &self, - tcx: TyCtxt<'tcx>, - self_ty: Ty<'tcx>, - ) -> ty::ProjectionPredicate<'tcx> { - // otherwise the escaping regions would be captured by the binders - debug_assert!(!self_ty.has_escaping_bound_vars()); - - ty::ProjectionPredicate { - projection_ty: AliasTy::new( - tcx, - self.def_id, - [self_ty.into()].into_iter().chain(self.args), - ), - term: self.term, - } - } - - pub fn erase_self_ty( - tcx: TyCtxt<'tcx>, - projection_predicate: ty::ProjectionPredicate<'tcx>, - ) -> Self { - // Assert there is a Self. - projection_predicate.projection_ty.args.type_at(0); - - Self { - def_id: projection_predicate.projection_ty.def_id, - args: tcx.mk_args(&projection_predicate.projection_ty.args[1..]), - term: projection_predicate.term, - } - } -} - impl<'tcx> PolyExistentialProjection<'tcx> { pub fn with_self_ty( &self, @@ -652,37 +466,8 @@ impl<'tcx> Clause<'tcx> { } } -#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct TraitPredicate<'tcx> { - pub trait_ref: TraitRef<'tcx>, - - /// If polarity is Positive: we are proving that the trait is implemented. - /// - /// If polarity is Negative: we are proving that a negative impl of this trait - /// exists. (Note that coherence also checks whether negative impls of supertraits - /// exist via a series of predicates.) - /// - /// If polarity is Reserved: that's a bug. - pub polarity: PredicatePolarity, -} - pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>; -impl<'tcx> TraitPredicate<'tcx> { - pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { - Self { trait_ref: self.trait_ref.with_self_ty(tcx, self_ty), ..self } - } - - pub fn def_id(self) -> DefId { - self.trait_ref.def_id - } - - pub fn self_ty(self) -> Ty<'tcx> { - self.trait_ref.self_ty() - } -} - impl<'tcx> PolyTraitPredicate<'tcx> { pub fn def_id(self) -> DefId { // Ok to skip binder since trait `DefId` does not care about regions. @@ -708,64 +493,10 @@ pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate, ty::Region<'t pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>; pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>; -/// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates -/// whether the `a` type is the type that we should label as "expected" when -/// presenting user diagnostics. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct SubtypePredicate<'tcx> { - pub a_is_expected: bool, - pub a: Ty<'tcx>, - pub b: Ty<'tcx>, -} pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>; -/// Encodes that we have to coerce *from* the `a` type to the `b` type. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct CoercePredicate<'tcx> { - pub a: Ty<'tcx>, - pub b: Ty<'tcx>, -} pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>; -/// This kind of predicate has no *direct* correspondent in the -/// syntax, but it roughly corresponds to the syntactic forms: -/// -/// 1. `T: TraitRef<..., Item = Type>` -/// 2. `>::Item == Type` (NYI) -/// -/// In particular, form #1 is "desugared" to the combination of a -/// normal trait predicate (`T: TraitRef<...>`) and one of these -/// predicates. Form #2 is a broader form in that it also permits -/// equality between arbitrary types. Processing an instance of -/// Form #2 eventually yields one of these `ProjectionPredicate` -/// instances to normalize the LHS. -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct ProjectionPredicate<'tcx> { - pub projection_ty: AliasTy<'tcx>, - pub term: Term<'tcx>, -} - -impl<'tcx> ProjectionPredicate<'tcx> { - pub fn self_ty(self) -> Ty<'tcx> { - self.projection_ty.self_ty() - } - - pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ProjectionPredicate<'tcx> { - Self { projection_ty: self.projection_ty.with_self_ty(tcx, self_ty), ..self } - } - - pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { - self.projection_ty.trait_def_id(tcx) - } - - pub fn def_id(self) -> DefId { - self.projection_ty.def_id - } -} - pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>; impl<'tcx> PolyProjectionPredicate<'tcx> { @@ -802,33 +533,6 @@ impl<'tcx> PolyProjectionPredicate<'tcx> { } } -/// Used by the new solver. Unlike a `ProjectionPredicate` this can only be -/// proven by actually normalizing `alias`. -#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] -#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)] -pub struct NormalizesTo<'tcx> { - pub alias: AliasTy<'tcx>, - pub term: Term<'tcx>, -} - -impl<'tcx> NormalizesTo<'tcx> { - pub fn self_ty(self) -> Ty<'tcx> { - self.alias.self_ty() - } - - pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> NormalizesTo<'tcx> { - Self { alias: self.alias.with_self_ty(tcx, self_ty), ..self } - } - - pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId { - self.alias.trait_def_id(tcx) - } - - pub fn def_id(self) -> DefId { - self.alias.def_id - } -} - pub trait ToPolyTraitRef<'tcx> { fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>; } diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 9d0e1123e43ac..e7589737d64b9 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -1,6 +1,7 @@ use crate::ty::GenericArg; use crate::ty::{self, Ty, TyCtxt}; +use hir::def::Namespace; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; use rustc_hir as hir; @@ -11,6 +12,8 @@ use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; mod pretty; pub use self::pretty::*; +use super::Lift; + pub type PrintError = std::fmt::Error; pub trait Print<'tcx, P> { @@ -157,7 +160,7 @@ pub trait Printer<'tcx>: Sized { // If we have any generic arguments to print, we do that // on top of the same path, but without its own generics. _ => { - if !generics.params.is_empty() && args.len() >= generics.count() { + if !generics.own_params.is_empty() && args.len() >= generics.count() { let args = generics.own_args_no_defaults(self.tcx(), args); return self.path_generic_args( |cx| cx.print_def_path(def_id, parent_args), @@ -334,3 +337,21 @@ pub fn describe_as_module(def_id: impl Into, tcx: TyCtxt<'_>) -> Str format!("module `{}`", tcx.def_path_str(def_id)) } } + +impl rustc_type_ir::ir_print::IrPrint for TyCtxt<'_> +where + T: Copy + for<'a, 'tcx> Lift, Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>>, +{ + fn print(t: &T, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ty::tls::with(|tcx| { + let mut cx = FmtPrinter::new(tcx, Namespace::TypeNS); + tcx.lift(*t).expect("could not lift for printing").print(&mut cx)?; + fmt.write_str(&cx.into_buffer())?; + Ok(()) + }) + } + + fn print_debug(t: &T, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + with_no_trimmed_paths!(Self::print(t, fmt)) + } +} diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 5f47aef0f32cb..be9525a083ce5 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -16,7 +16,7 @@ use rustc_hir::def::{self, CtorKind, DefKind, Namespace}; use rustc_hir::def_id::{DefIdMap, DefIdSet, ModDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPathDataName}; use rustc_hir::LangItem; -use rustc_macros::Lift; +use rustc_macros::{extension, Lift}; use rustc_session::cstore::{ExternCrate, ExternCrateSource}; use rustc_session::Limit; use rustc_span::symbol::{kw, Ident, Symbol}; @@ -977,7 +977,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { fn pretty_print_opaque_impl_type( &mut self, def_id: DefId, - args: &'tcx ty::List>, + args: ty::GenericArgsRef<'tcx>, ) -> Result<(), PrintError> { let tcx = self.tcx(); @@ -2919,16 +2919,17 @@ impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitName<'tcx> { } } +#[extension(pub trait PrintTraitRefExt<'tcx>)] impl<'tcx> ty::TraitRef<'tcx> { - pub fn print_only_trait_path(self) -> TraitRefPrintOnlyTraitPath<'tcx> { + fn print_only_trait_path(self) -> TraitRefPrintOnlyTraitPath<'tcx> { TraitRefPrintOnlyTraitPath(self) } - pub fn print_trait_sugared(self) -> TraitRefPrintSugared<'tcx> { + fn print_trait_sugared(self) -> TraitRefPrintSugared<'tcx> { TraitRefPrintSugared(self) } - pub fn print_only_trait_name(self) -> TraitRefPrintOnlyTraitName<'tcx> { + fn print_only_trait_name(self) -> TraitRefPrintOnlyTraitName<'tcx> { TraitRefPrintOnlyTraitName(self) } } @@ -2952,8 +2953,9 @@ impl<'tcx> fmt::Debug for TraitPredPrintModifiersAndPath<'tcx> { } } +#[extension(pub trait PrintTraitPredicateExt<'tcx>)] impl<'tcx> ty::TraitPredicate<'tcx> { - pub fn print_modifiers_and_trait_path(self) -> TraitPredPrintModifiersAndPath<'tcx> { + fn print_modifiers_and_trait_path(self) -> TraitPredPrintModifiersAndPath<'tcx> { TraitPredPrintModifiersAndPath(self) } } @@ -3032,6 +3034,19 @@ forward_display_to_print! { define_print! { (self, cx): + ty::TraitRef<'tcx> { + p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path())) + } + + ty::TraitPredicate<'tcx> { + p!(print(self.trait_ref.self_ty()), ": "); + p!(pretty_print_bound_constness(self.trait_ref)); + if let ty::PredicatePolarity::Negative = self.polarity { + p!("!"); + } + p!(print(self.trait_ref.print_trait_sugared())) + } + ty::TypeAndMut<'tcx> { p!(write("{}", self.mutbl.prefix_str()), print(self.ty)) } @@ -3072,13 +3087,15 @@ define_print! { ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)), } } -} - -define_print_and_forward_display! { - (self, cx): - &'tcx ty::List> { - p!("{{", comma_sep(self.iter()), "}}") + ty::ExistentialPredicate<'tcx> { + match *self { + ty::ExistentialPredicate::Trait(x) => p!(print(x)), + ty::ExistentialPredicate::Projection(x) => p!(print(x)), + ty::ExistentialPredicate::AutoTrait(def_id) => { + p!(print_def_path(def_id, &[])); + } + } } ty::ExistentialTraitRef<'tcx> { @@ -3093,14 +3110,36 @@ define_print_and_forward_display! { p!(write("{} = ", name), print(self.term)) } - ty::ExistentialPredicate<'tcx> { - match *self { - ty::ExistentialPredicate::Trait(x) => p!(print(x)), - ty::ExistentialPredicate::Projection(x) => p!(print(x)), - ty::ExistentialPredicate::AutoTrait(def_id) => { - p!(print_def_path(def_id, &[])); - } - } + ty::ProjectionPredicate<'tcx> { + p!(print(self.projection_ty), " == "); + cx.reset_type_limit(); + p!(print(self.term)) + } + + ty::SubtypePredicate<'tcx> { + p!(print(self.a), " <: "); + cx.reset_type_limit(); + p!(print(self.b)) + } + + ty::CoercePredicate<'tcx> { + p!(print(self.a), " -> "); + cx.reset_type_limit(); + p!(print(self.b)) + } + + ty::NormalizesTo<'tcx> { + p!(print(self.alias), " normalizes-to "); + cx.reset_type_limit(); + p!(print(self.term)) + } +} + +define_print_and_forward_display! { + (self, cx): + + &'tcx ty::List> { + p!("{{", comma_sep(self.iter()), "}}") } ty::FnSig<'tcx> { @@ -3113,10 +3152,6 @@ define_print_and_forward_display! { p!("fn", pretty_fn_sig(self.inputs(), self.c_variadic, self.output())); } - ty::TraitRef<'tcx> { - p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path())) - } - TraitRefPrintOnlyTraitPath<'tcx> { p!(print_def_path(self.0.def_id, self.0.args)); } @@ -3163,39 +3198,6 @@ define_print_and_forward_display! { p!(write("{}", self.name)) } - ty::SubtypePredicate<'tcx> { - p!(print(self.a), " <: "); - cx.reset_type_limit(); - p!(print(self.b)) - } - - ty::CoercePredicate<'tcx> { - p!(print(self.a), " -> "); - cx.reset_type_limit(); - p!(print(self.b)) - } - - ty::TraitPredicate<'tcx> { - p!(print(self.trait_ref.self_ty()), ": "); - p!(pretty_print_bound_constness(self.trait_ref)); - if let ty::PredicatePolarity::Negative = self.polarity { - p!("!"); - } - p!(print(self.trait_ref.print_trait_sugared())) - } - - ty::ProjectionPredicate<'tcx> { - p!(print(self.projection_ty), " == "); - cx.reset_type_limit(); - p!(print(self.term)) - } - - ty::NormalizesTo<'tcx> { - p!(print(self.alias), " normalizes-to "); - cx.reset_type_limit(); - p!(print(self.term)) - } - ty::Term<'tcx> { match self.unpack() { ty::TermKind::Ty(ty) => p!(print(ty)), diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 3d9be15310fee..8842ecd12e98f 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -19,7 +19,7 @@ pub type RegionKind<'tcx> = IrRegionKind>; #[rustc_pass_by_value] pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>); -impl<'tcx> rustc_type_ir::IntoKind for Region<'tcx> { +impl<'tcx> rustc_type_ir::inherent::IntoKind for Region<'tcx> { type Kind = RegionKind<'tcx>; fn kind(self) -> RegionKind<'tcx> { @@ -137,7 +137,7 @@ impl<'tcx> Region<'tcx> { } } -impl<'tcx> rustc_type_ir::new::Region> for Region<'tcx> { +impl<'tcx> rustc_type_ir::inherent::Region> for Region<'tcx> { fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::BrAnon }) } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 7063ef07201bb..417edda10caeb 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -5,8 +5,10 @@ //! subtyping, type equality, etc. use crate::ty::error::{ExpectedFound, TypeError}; -use crate::ty::{self, Expr, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable}; -use crate::ty::{GenericArg, GenericArgKind, GenericArgsRef}; +use crate::ty::{ + self, ExistentialPredicate, ExistentialPredicateStableCmpExt as _, Expr, GenericArg, + GenericArgKind, GenericArgsRef, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable, +}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -702,14 +704,21 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List> { } let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| { - use crate::ty::ExistentialPredicate::*; match (ep_a.skip_binder(), ep_b.skip_binder()) { - (Trait(a), Trait(b)) => Ok(ep_a - .rebind(Trait(relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder()))), - (Projection(a), Projection(b)) => Ok(ep_a.rebind(Projection( - relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), - ))), - (AutoTrait(a), AutoTrait(b)) if a == b => Ok(ep_a.rebind(AutoTrait(a))), + (ExistentialPredicate::Trait(a), ExistentialPredicate::Trait(b)) => Ok(ep_a + .rebind(ExistentialPredicate::Trait( + relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), + ))), + (ExistentialPredicate::Projection(a), ExistentialPredicate::Projection(b)) => { + Ok(ep_a.rebind(ExistentialPredicate::Projection( + relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), + ))) + } + (ExistentialPredicate::AutoTrait(a), ExistentialPredicate::AutoTrait(b)) + if a == b => + { + Ok(ep_a.rebind(ExistentialPredicate::AutoTrait(a))) + } _ => Err(TypeError::ExistentialMismatch(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 14a77d4b37ec7..dc071b295aad3 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -55,12 +55,6 @@ impl fmt::Debug for ty::UpvarId { } } -impl<'tcx> fmt::Debug for ty::ExistentialTraitRef<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - with_no_trimmed_paths!(fmt::Display::fmt(self, f)) - } -} - impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?} -> {}", self.kind, self.target) @@ -132,12 +126,6 @@ impl<'tcx> DebugWithInfcx> for ty::FnSig<'tcx> { } } -impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - with_no_trimmed_paths!(fmt::Display::fmt(self, f)) - } -} - impl<'tcx> ty::DebugWithInfcx> for Ty<'tcx> { fn fmt>>( this: WithInfcx<'_, Infcx, &Self>, @@ -164,25 +152,6 @@ impl fmt::Debug for ty::ParamConst { } } -impl<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // FIXME(effects) printing? - write!(f, "TraitPredicate({:?}, polarity:{:?})", self.trait_ref, self.polarity) - } -} - -impl<'tcx> fmt::Debug for ty::ProjectionPredicate<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_ty, self.term) - } -} - -impl<'tcx> fmt::Debug for ty::NormalizesTo<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "NormalizesTo({:?}, {:?})", self.alias, self.term) - } -} - impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self.kind()) @@ -478,7 +447,7 @@ TrivialTypeTraversalAndLiftImpls! { /////////////////////////////////////////////////////////////////////////// // Lift implementations -impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option { +impl<'tcx, T: Lift>> Lift> for Option { type Lifted = Option; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { Some(match self { @@ -488,7 +457,7 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option { } } -impl<'a, 'tcx> Lift<'tcx> for Term<'a> { +impl<'a, 'tcx> Lift> for Term<'a> { type Lifted = ty::Term<'tcx>; fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option { Some( diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index de70c4f7b65a1..1fc8eefd65fb1 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -942,7 +942,7 @@ where } } -impl<'tcx, T> rustc_type_ir::BoundVars> for ty::Binder<'tcx, T> { +impl<'tcx, T> rustc_type_ir::inherent::BoundVars> for ty::Binder<'tcx, T> { fn bound_vars(&self) -> &'tcx List { self.bound_vars } @@ -1142,6 +1142,36 @@ pub struct AliasTy<'tcx> { _use_alias_ty_new_instead: (), } +impl<'tcx> rustc_type_ir::inherent::AliasTy> for AliasTy<'tcx> { + fn new( + interner: TyCtxt<'tcx>, + trait_def_id: DefId, + args: impl IntoIterator>>, + ) -> Self { + AliasTy::new(interner, trait_def_id, args) + } + + fn def_id(self) -> DefId { + self.def_id + } + + fn args(self) -> ty::GenericArgsRef<'tcx> { + self.args + } + + fn trait_def_id(self, interner: TyCtxt<'tcx>) -> DefId { + self.trait_def_id(interner) + } + + fn self_ty(self) -> Ty<'tcx> { + self.self_ty() + } + + fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { + self.with_self_ty(tcx, self_ty) + } +} + impl<'tcx> AliasTy<'tcx> { pub fn new( tcx: TyCtxt<'tcx>, @@ -1812,7 +1842,7 @@ impl<'tcx> Ty<'tcx> { } } -impl<'tcx> rustc_type_ir::new::Ty> for Ty<'tcx> { +impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon }) } @@ -2164,13 +2194,11 @@ impl<'tcx> Ty<'tcx> { /// /// The parameter `explicit` indicates if this is an *explicit* dereference. /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly. - pub fn builtin_deref(self, explicit: bool) -> Option> { - match self.kind() { - Adt(def, _) if def.is_box() => { - Some(TypeAndMut { ty: self.boxed_ty(), mutbl: hir::Mutability::Not }) - } - Ref(_, ty, mutbl) => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }), - RawPtr(ty, mutbl) if explicit => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }), + pub fn builtin_deref(self, explicit: bool) -> Option> { + match *self.kind() { + Adt(def, _) if def.is_box() => Some(self.boxed_ty()), + Ref(_, ty, _) => Some(ty), + RawPtr(ty, _) if explicit => Some(ty), _ => None, } } diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 41f417dfd4b1a..24e3e623ff274 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -79,6 +79,10 @@ pub struct TypeckResults<'tcx> { /// Stores the actual binding mode for all instances of [`BindingMode`]. pat_binding_modes: ItemLocalMap, + /// Top-level patterns whose match ergonomics need to be desugared + /// by the Rust 2021 -> 2024 migration lint. + rust_2024_migration_desugared_pats: ItemLocalSet, + /// Stores the types which were implicitly dereferenced in pattern binding modes /// for later usage in THIR lowering. For example, /// @@ -229,6 +233,7 @@ impl<'tcx> TypeckResults<'tcx> { adjustments: Default::default(), pat_binding_modes: Default::default(), pat_adjustments: Default::default(), + rust_2024_migration_desugared_pats: Default::default(), skipped_ref_pats: Default::default(), closure_kind_origins: Default::default(), liberated_fn_sigs: Default::default(), @@ -432,6 +437,20 @@ impl<'tcx> TypeckResults<'tcx> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments } } + pub fn rust_2024_migration_desugared_pats(&self) -> LocalSetInContext<'_> { + LocalSetInContext { + hir_owner: self.hir_owner, + data: &self.rust_2024_migration_desugared_pats, + } + } + + pub fn rust_2024_migration_desugared_pats_mut(&mut self) -> LocalSetInContextMut<'_> { + LocalSetInContextMut { + hir_owner: self.hir_owner, + data: &mut self.rust_2024_migration_desugared_pats, + } + } + pub fn skipped_ref_pats(&self) -> LocalSetInContext<'_> { LocalSetInContext { hir_owner: self.hir_owner, data: &self.skipped_ref_pats } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index f5e973f85da12..6ad4f492f742f 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -2,7 +2,7 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::query::{IntoQueryParam, Providers}; -use crate::ty::layout::IntegerExt; +use crate::ty::layout::{FloatExt, IntegerExt}; use crate::ty::{ self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, @@ -20,7 +20,7 @@ use rustc_index::bit_set::GrowableBitSet; use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable}; use rustc_session::Limit; use rustc_span::sym; -use rustc_target::abi::{Integer, IntegerType, Primitive, Size}; +use rustc_target::abi::{Float, Integer, IntegerType, Size}; use rustc_target::spec::abi::Abi; use smallvec::{smallvec, SmallVec}; use std::{fmt, iter}; @@ -1145,8 +1145,7 @@ impl<'tcx> Ty<'tcx> { ty::Char => Size::from_bytes(4), ty::Int(ity) => Integer::from_int_ty(&tcx, ity).size(), ty::Uint(uty) => Integer::from_uint_ty(&tcx, uty).size(), - ty::Float(ty::FloatTy::F32) => Primitive::F32.size(&tcx), - ty::Float(ty::FloatTy::F64) => Primitive::F64.size(&tcx), + ty::Float(fty) => Float::from_float_ty(fty).size(), _ => bug!("non primitive type"), } } diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 5c17c0b3088fe..e3866b27ceef1 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -141,7 +141,7 @@ impl<'tcx> Value> for &[ty::Variance] { && frame.query.dep_kind == dep_kinds::variances_of && let Some(def_id) = frame.query.def_id { - let n = tcx.generics_of(def_id).params.len(); + let n = tcx.generics_of(def_id).own_params.len(); vec![ty::Variance::Bivariant; n].leak() } else { span_bug!( diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index 6618e4f5a0024..77f27236437dd 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -16,6 +16,7 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_infer = { path = "../rustc_infer" } +rustc_lint = { path = "../rustc_lint" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_pattern_analysis = { path = "../rustc_pattern_analysis" } diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 34440c60cf378..0bb44dbb8706b 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -267,6 +267,8 @@ mir_build_pointer_pattern = function pointers and raw pointers not derived from mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future +mir_build_rust_2024_incompatible_pat = the semantics of this pattern will change in edition 2024 + mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly .attributes = no other attributes may be applied .not_box = `#[rustc_box]` may only be applied to a `Box::new()` call diff --git a/compiler/rustc_mir_build/src/build/coverageinfo.rs b/compiler/rustc_mir_build/src/build/coverageinfo.rs index e2a5f97a84744..ee9eeb62990d2 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo.rs @@ -1,17 +1,18 @@ -mod mcdc; use std::assert_matches::assert_matches; use std::collections::hash_map::Entry; use rustc_data_structures::fx::FxHashMap; use rustc_middle::mir::coverage::{BlockMarkerId, BranchSpan, CoverageKind}; use rustc_middle::mir::{self, BasicBlock, SourceInfo, UnOp}; -use rustc_middle::thir::{ExprId, ExprKind, Thir}; +use rustc_middle::thir::{ExprId, ExprKind, Pat, Thir}; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::LocalDefId; use crate::build::coverageinfo::mcdc::MCDCInfoBuilder; use crate::build::{Builder, CFG}; +mod mcdc; + pub(crate) struct BranchInfoBuilder { /// Maps condition expressions to their enclosing `!`, for better instrumentation. nots: FxHashMap, @@ -155,7 +156,7 @@ impl BranchInfoBuilder { } } -impl Builder<'_, '_> { +impl<'tcx> Builder<'_, 'tcx> { /// If branch coverage is enabled, inject marker statements into `then_block` /// and `else_block`, and record their IDs in the table of branch spans. pub(crate) fn visit_coverage_branch_condition( @@ -195,4 +196,23 @@ impl Builder<'_, '_> { branch_info.add_two_way_branch(&mut self.cfg, source_info, then_block, else_block); } + + /// If branch coverage is enabled, inject marker statements into `true_block` + /// and `false_block`, and record their IDs in the table of branches. + /// + /// Used to instrument let-else and if-let (including let-chains) for branch coverage. + pub(crate) fn visit_coverage_conditional_let( + &mut self, + pattern: &Pat<'tcx>, // Pattern that has been matched when the true path is taken + true_block: BasicBlock, + false_block: BasicBlock, + ) { + // Bail out if branch coverage is not enabled for this function. + let Some(branch_info) = self.coverage_branch_info.as_mut() else { return }; + + // FIXME(#124144) This may need special handling when MC/DC is enabled. + + let source_info = SourceInfo { span: pattern.span, scope: self.source_scope }; + branch_info.add_two_way_branch(&mut self.cfg, source_info, true_block, false_block); + } } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index bce1526775963..7cf4fac731b41 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1016,6 +1016,9 @@ struct PatternExtraData<'tcx> { /// Types that must be asserted. ascriptions: Vec>, + + /// Whether this corresponds to a never pattern. + is_never: bool, } impl<'tcx> PatternExtraData<'tcx> { @@ -1041,12 +1044,14 @@ impl<'tcx, 'pat> FlatPat<'pat, 'tcx> { pattern: &'pat Pat<'tcx>, cx: &mut Builder<'_, 'tcx>, ) -> Self { + let is_never = pattern.is_never_pattern(); let mut flat_pat = FlatPat { match_pairs: vec![MatchPair::new(place, pattern, cx)], extra_data: PatternExtraData { span: pattern.span, bindings: Vec::new(), ascriptions: Vec::new(), + is_never, }, }; cx.simplify_match_pairs(&mut flat_pat.match_pairs, &mut flat_pat.extra_data); @@ -1062,6 +1067,8 @@ struct Candidate<'pat, 'tcx> { match_pairs: Vec>, /// ...and if this is non-empty, one of these subcandidates also has to match... + // Invariant: at the end of the algorithm, this must never contain a `is_never` candidate + // because that would break binding consistency. subcandidates: Vec>, /// ...and the guard must be evaluated if there is one. @@ -1172,6 +1179,7 @@ enum TestCase<'pat, 'tcx> { Range(&'pat PatRange<'tcx>), Slice { len: usize, variable_length: bool }, Deref { temp: Place<'tcx>, mutability: Mutability }, + Never, Or { pats: Box<[FlatPat<'pat, 'tcx>]> }, } @@ -1238,6 +1246,9 @@ enum TestKind<'tcx> { temp: Place<'tcx>, mutability: Mutability, }, + + /// Assert unreachability of never patterns. + Never, } /// A test to perform to determine which [`Candidate`] matches a value. @@ -1662,6 +1673,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.goto(or_block, source_info, any_matches); } candidate.pre_binding_block = Some(any_matches); + } else { + // Never subcandidates may have a set of bindings inconsistent with their siblings, + // which would break later code. So we filter them out. Note that we can't filter out + // top-level candidates this way. + candidate.subcandidates.retain_mut(|candidate| { + if candidate.extra_data.is_never { + candidate.visit_leaves(|subcandidate| { + let block = subcandidate.pre_binding_block.unwrap(); + // That block is already unreachable but needs a terminator to make the MIR well-formed. + let source_info = self.source_info(subcandidate.extra_data.span); + self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + }); + false + } else { + true + } + }); + if candidate.subcandidates.is_empty() { + // If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block`. + candidate.pre_binding_block = Some(self.cfg.start_new_block()); + } } } @@ -1968,6 +2000,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { false, ); + // If branch coverage is enabled, record this branch. + self.visit_coverage_conditional_let(pat, post_guard_block, otherwise_post_guard_block); + post_guard_block.unit() } @@ -2008,6 +2043,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block = fresh_block; } + if candidate.extra_data.is_never { + // This arm has a dummy body, we don't need to generate code for it. `block` is already + // unreachable (except via false edge). + let source_info = self.source_info(candidate.extra_data.span); + self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + return self.cfg.start_new_block(); + } + self.ascribe_types( block, parent_data @@ -2452,6 +2495,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, true, ); + + // If branch coverage is enabled, record this branch. + this.visit_coverage_conditional_let(pattern, matching, failure); + this.break_for_else(failure, this.source_info(initializer_span)); matching.unit() }); diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 5dd478aa4224a..7f65697fa4b2b 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -44,6 +44,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestCase::Deref { temp, mutability } => TestKind::Deref { temp, mutability }, + TestCase::Never => TestKind::Never, + TestCase::Or { .. } => bug!("or-patterns should have already been handled"), TestCase::Irrefutable { .. } => span_bug!( @@ -262,6 +264,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let target = target_block(TestBranch::Success); self.call_deref(block, target, place, mutability, ty, temp, test.span); } + + TestKind::Never => { + // Check that the place is initialized. + // FIXME(never_patterns): Also assert validity of the data at `place`. + self.cfg.push_fake_read( + block, + source_info, + FakeReadCause::ForMatchedPlace(None), + place, + ); + // A never pattern is only allowed on an uninhabited type, so validity of the data + // implies unreachability. + self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + } } } @@ -710,6 +726,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(TestBranch::Success) } + (TestKind::Never, _) => { + fully_matched = true; + Some(TestBranch::Success) + } + ( TestKind::Switch { .. } | TestKind::SwitchInt { .. } diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 2f9390c22a89d..14c74c761ebb3 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -2,7 +2,6 @@ use crate::build::expr::as_place::{PlaceBase, PlaceBuilder}; use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase}; use crate::build::Builder; use rustc_data_structures::fx::FxIndexMap; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_middle::mir::*; use rustc_middle::thir::{self, *}; use rustc_middle::ty::TypeVisitableExt; @@ -124,7 +123,8 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None }; let mut subpairs = Vec::new(); let test_case = match pattern.kind { - PatKind::Never | PatKind::Wild | PatKind::Error(_) => default_irrefutable(), + PatKind::Wild | PatKind::Error(_) => default_irrefutable(), + PatKind::Or { ref pats } => TestCase::Or { pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(), }, @@ -179,9 +179,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { cx.tcx, ty::InlineConstArgsParts { parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id), - ty: cx - .infcx - .next_ty_var(TypeVariableOrigin { param_def_id: None, span }), + ty: cx.infcx.next_ty_var(span), }, ) .args; @@ -260,6 +258,8 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx)); TestCase::Deref { temp, mutability } } + + PatKind::Never => TestCase::Never, }; MatchPair { place, test_case, subpairs, pattern } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index f67113afd6d9d..e2a28467b8457 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -950,3 +950,30 @@ pub enum RustcBoxAttrReason { #[note(mir_build_missing_box)] MissingBox, } + +#[derive(LintDiagnostic)] +#[diag(mir_build_rust_2024_incompatible_pat)] +pub struct Rust2024IncompatiblePat { + #[subdiagnostic] + pub sugg: Rust2024IncompatiblePatSugg, +} + +pub struct Rust2024IncompatiblePatSugg { + pub suggestion: Vec<(Span, String)>, +} + +impl Subdiagnostic for Rust2024IncompatiblePatSugg { + fn add_to_diag_with>( + self, + diag: &mut Diag<'_, G>, + _f: &F, + ) { + let applicability = + if self.suggestion.iter().all(|(span, _)| span.can_be_used_for_suggestions()) { + Applicability::MachineApplicable + } else { + Applicability::MaybeIncorrect + }; + diag.multipart_suggestion("desugar the match ergonomics", self.suggestion, applicability); + } +} diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 5c016682d8d2d..48fc0293f4058 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -11,8 +11,9 @@ use crate::thir::util::UserAnnotatedTyHelpers; use rustc_errors::codes::*; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; -use rustc_hir::{self as hir, RangeEnd}; +use rustc_hir::{self as hir, ByRef, Mutability, RangeEnd}; use rustc_index::Idx; +use rustc_lint as lint; use rustc_middle::mir::interpret::{ErrorHandled, GlobalId, LitToConstError, LitToConstInput}; use rustc_middle::mir::{self, Const}; use rustc_middle::thir::{ @@ -30,6 +31,9 @@ struct PatCtxt<'a, 'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, + + /// Used by the Rust 2024 migration lint. + rust_2024_migration_suggestion: Option, } pub(super) fn pat_from_hir<'a, 'tcx>( @@ -38,9 +42,25 @@ pub(super) fn pat_from_hir<'a, 'tcx>( typeck_results: &'a ty::TypeckResults<'tcx>, pat: &'tcx hir::Pat<'tcx>, ) -> Box> { - let mut pcx = PatCtxt { tcx, param_env, typeck_results }; + let mut pcx = PatCtxt { + tcx, + param_env, + typeck_results, + rust_2024_migration_suggestion: typeck_results + .rust_2024_migration_desugared_pats() + .contains(pat.hir_id) + .then_some(Rust2024IncompatiblePatSugg { suggestion: Vec::new() }), + }; let result = pcx.lower_pattern(pat); debug!("pat_from_hir({:?}) = {:?}", pat, result); + if let Some(sugg) = pcx.rust_2024_migration_suggestion { + tcx.emit_node_span_lint( + lint::builtin::RUST_2024_INCOMPATIBLE_PAT, + pat.hir_id, + pat.span, + Rust2024IncompatiblePat { sugg }, + ); + } result } @@ -73,17 +93,38 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } _ => self.lower_pattern_unadjusted(pat), }; - self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold( - unadjusted_pat, - |pat: Box<_>, ref_ty| { - debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty); - Box::new(Pat { - span: pat.span, - ty: *ref_ty, - kind: PatKind::Deref { subpattern: pat }, + + let adjustments: &[Ty<'tcx>] = + self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v); + let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, ref_ty| { + debug!("{:?}: wrapping pattern with type {:?}", thir_pat, ref_ty); + Box::new(Pat { + span: thir_pat.span, + ty: *ref_ty, + kind: PatKind::Deref { subpattern: thir_pat }, + }) + }); + + if let Some(s) = &mut self.rust_2024_migration_suggestion + && !adjustments.is_empty() + { + let suggestion_str: String = adjustments + .iter() + .map(|ref_ty| { + let &ty::Ref(_, _, mutbl) = ref_ty.kind() else { + span_bug!(pat.span, "pattern implicitly dereferences a non-ref type"); + }; + + match mutbl { + ty::Mutability::Not => "&", + ty::Mutability::Mut => "&mut ", + } }) - }, - ) + .collect(); + s.suggestion.push((pat.span.shrink_to_lo(), suggestion_str)); + }; + + adjusted_pat } fn lower_pattern_range_endpoint( @@ -272,7 +313,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { PatKind::Deref { subpattern: self.lower_pattern(subpattern) } } - hir::PatKind::Slice(prefix, ref slice, suffix) => { + hir::PatKind::Slice(prefix, slice, suffix) => { self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix) } @@ -284,7 +325,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { PatKind::Leaf { subpatterns } } - hir::PatKind::Binding(_, id, ident, ref sub) => { + hir::PatKind::Binding(explicit_ba, id, ident, sub) => { if let Some(ident_span) = ident.span.find_ancestor_inside(span) { span = span.with_hi(ident_span.hi()); } @@ -295,6 +336,20 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { .get(pat.hir_id) .expect("missing binding mode"); + if let Some(s) = &mut self.rust_2024_migration_suggestion + && explicit_ba.0 == ByRef::No + && let ByRef::Yes(mutbl) = mode.0 + { + let sugg_str = match mutbl { + Mutability::Not => "ref ", + Mutability::Mut => "ref mut ", + }; + s.suggestion.push(( + pat.span.with_lo(ident.span.lo()).shrink_to_lo(), + sugg_str.to_owned(), + )) + } + // A ref x pattern is the same node used for x, and as such it has // x's type, which is &T, where we want T (the type being matched). let var_ty = ty; @@ -366,10 +421,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { pats.iter().map(|p| self.lower_pattern(p)).collect() } - fn lower_opt_pattern( - &mut self, - pat: &'tcx Option<&'tcx hir::Pat<'tcx>>, - ) -> Option>> { + fn lower_opt_pattern(&mut self, pat: Option<&'tcx hir::Pat<'tcx>>) -> Option>> { pat.map(|p| self.lower_pattern(p)) } @@ -378,7 +430,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { span: Span, ty: Ty<'tcx>, prefix: &'tcx [hir::Pat<'tcx>], - slice: &'tcx Option<&'tcx hir::Pat<'tcx>>, + slice: Option<&'tcx hir::Pat<'tcx>>, suffix: &'tcx [hir::Pat<'tcx>], ) -> PatKind<'tcx> { let prefix = self.lower_patterns(prefix); diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index 0af8872988754..5199c41c58cd4 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -106,7 +106,7 @@ impl<'tcx, 'a> Visitor<'tcx> for PointerFinder<'tcx, 'a> { } let pointee_ty = - pointer_ty.builtin_deref(true).expect("no builtin_deref for an unsafe pointer").ty; + pointer_ty.builtin_deref(true).expect("no builtin_deref for an unsafe pointer"); // Ideally we'd support this in the future, but for now we are limited to sized types. if !pointee_ty.is_sized(self.tcx, self.param_env) { debug!("Unsafe pointer, but pointee is not known to be sized: {:?}", pointer_ty); diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index ddbe1333c4b08..61aabea1d8b31 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -52,104 +52,104 @@ pub(super) struct MCDCDecision { pub(super) decision_depth: u16, } -pub(super) struct CoverageSpans { - bcb_has_mappings: BitSet, +#[derive(Default)] +pub(super) struct ExtractedMappings { pub(super) code_mappings: Vec, pub(super) branch_pairs: Vec, - test_vector_bitmap_bytes: u32, + pub(super) mcdc_bitmap_bytes: u32, pub(super) mcdc_branches: Vec, pub(super) mcdc_decisions: Vec, } -impl CoverageSpans { - pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool { - self.bcb_has_mappings.contains(bcb) - } - - pub(super) fn test_vector_bitmap_bytes(&self) -> u32 { - self.test_vector_bitmap_bytes - } -} - /// Extracts coverage-relevant spans from MIR, and associates them with /// their corresponding BCBs. -/// -/// Returns `None` if no coverage-relevant spans could be extracted. -pub(super) fn generate_coverage_spans( +pub(super) fn extract_all_mapping_info_from_mir( mir_body: &mir::Body<'_>, hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, -) -> Option { - let mut code_mappings = vec![]; - let mut branch_pairs = vec![]; - let mut mcdc_branches = vec![]; - let mut mcdc_decisions = vec![]; - +) -> ExtractedMappings { if hir_info.is_async_fn { // An async function desugars into a function that returns a future, // with the user code wrapped in a closure. Any spans in the desugared // outer function will be unhelpful, so just keep the signature span // and ignore all of the spans in the MIR body. + let mut mappings = ExtractedMappings::default(); if let Some(span) = hir_info.fn_sig_span_extended { - code_mappings.push(CodeMapping { span, bcb: START_BCB }); + mappings.code_mappings.push(CodeMapping { span, bcb: START_BCB }); } - } else { - extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings); - - branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks)); - - extract_mcdc_mappings( - mir_body, - hir_info.body_span, - basic_coverage_blocks, - &mut mcdc_branches, - &mut mcdc_decisions, - ); + return mappings; } - if code_mappings.is_empty() - && branch_pairs.is_empty() - && mcdc_branches.is_empty() - && mcdc_decisions.is_empty() - { - return None; - } + let mut code_mappings = vec![]; + let mut branch_pairs = vec![]; + let mut mcdc_bitmap_bytes = 0; + let mut mcdc_branches = vec![]; + let mut mcdc_decisions = vec![]; - // Identify which BCBs have one or more mappings. - let mut bcb_has_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes()); - let mut insert = |bcb| { - bcb_has_mappings.insert(bcb); - }; + extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings); - for &CodeMapping { span: _, bcb } in &code_mappings { - insert(bcb); - } - for &BranchPair { true_bcb, false_bcb, .. } in &branch_pairs { - insert(true_bcb); - insert(false_bcb); - } - for &MCDCBranch { true_bcb, false_bcb, .. } in &mcdc_branches { - insert(true_bcb); - insert(false_bcb); - } + branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks)); - // Determine the length of the test vector bitmap. - let test_vector_bitmap_bytes = mcdc_decisions - .iter() - .map(|&MCDCDecision { bitmap_idx, conditions_num, .. }| { - bitmap_idx + (1_u32 << u32::from(conditions_num)).div_ceil(8) - }) - .max() - .unwrap_or(0); + extract_mcdc_mappings( + mir_body, + hir_info.body_span, + basic_coverage_blocks, + &mut mcdc_bitmap_bytes, + &mut mcdc_branches, + &mut mcdc_decisions, + ); - Some(CoverageSpans { - bcb_has_mappings, + ExtractedMappings { code_mappings, branch_pairs, - test_vector_bitmap_bytes, + mcdc_bitmap_bytes, mcdc_branches, mcdc_decisions, - }) + } +} + +impl ExtractedMappings { + pub(super) fn all_bcbs_with_counter_mappings( + &self, + basic_coverage_blocks: &CoverageGraph, // Only used for allocating a correctly-sized set + ) -> BitSet { + // Fully destructure self to make sure we don't miss any fields that have mappings. + let Self { + code_mappings, + branch_pairs, + mcdc_bitmap_bytes: _, + mcdc_branches, + mcdc_decisions, + } = self; + + // Identify which BCBs have one or more mappings. + let mut bcbs_with_counter_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes()); + let mut insert = |bcb| { + bcbs_with_counter_mappings.insert(bcb); + }; + + for &CodeMapping { span: _, bcb } in code_mappings { + insert(bcb); + } + for &BranchPair { true_bcb, false_bcb, .. } in branch_pairs { + insert(true_bcb); + insert(false_bcb); + } + for &MCDCBranch { true_bcb, false_bcb, .. } in mcdc_branches { + insert(true_bcb); + insert(false_bcb); + } + + // MC/DC decisions refer to BCBs, but don't require those BCBs to have counters. + if bcbs_with_counter_mappings.is_empty() { + debug_assert!( + mcdc_decisions.is_empty(), + "A function with no counter mappings shouldn't have any decisions: {mcdc_decisions:?}", + ); + } + + bcbs_with_counter_mappings + } } fn resolve_block_markers( @@ -215,6 +215,7 @@ pub(super) fn extract_mcdc_mappings( mir_body: &mir::Body<'_>, body_span: Span, basic_coverage_blocks: &CoverageGraph, + mcdc_bitmap_bytes: &mut u32, mcdc_branches: &mut impl Extend, mcdc_decisions: &mut impl Extend, ) { @@ -253,8 +254,6 @@ pub(super) fn extract_mcdc_mappings( }, )); - let mut next_bitmap_idx = 0; - mcdc_decisions.extend(branch_info.mcdc_decision_spans.iter().filter_map( |decision: &mir::coverage::MCDCDecisionSpan| { let (span, _) = unexpand_into_body_span_with_visible_macro(decision.span, body_span)?; @@ -265,8 +264,11 @@ pub(super) fn extract_mcdc_mappings( .map(|&marker| bcb_from_marker(marker)) .collect::>()?; - let bitmap_idx = next_bitmap_idx; - next_bitmap_idx += (1_u32 << decision.conditions_num).div_ceil(8); + // Each decision containing N conditions needs 2^N bits of space in + // the bitmap, rounded up to a whole number of bytes. + // The decision's "bitmap index" points to its first byte in the bitmap. + let bitmap_idx = *mcdc_bitmap_bytes; + *mcdc_bitmap_bytes += (1_u32 << decision.conditions_num).div_ceil(8); Some(MCDCDecision { span, diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 1e2599e78e9e1..28e0c633d5aaa 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -7,13 +7,9 @@ mod spans; #[cfg(test)] mod tests; -use self::counters::{CounterIncrementSite, CoverageCounters}; -use self::graph::{BasicCoverageBlock, CoverageGraph}; -use self::mappings::CoverageSpans; - -use crate::MirPass; - -use rustc_middle::mir::coverage::*; +use rustc_middle::mir::coverage::{ + CodeRegion, CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind, +}; use rustc_middle::mir::{ self, BasicBlock, BasicBlockData, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, @@ -23,6 +19,11 @@ use rustc_span::def_id::LocalDefId; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol}; +use crate::coverage::counters::{CounterIncrementSite, CoverageCounters}; +use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; +use crate::coverage::mappings::ExtractedMappings; +use crate::MirPass; + /// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected /// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen /// to construct the coverage map. @@ -69,24 +70,27 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); //////////////////////////////////////////////////// - // Compute coverage spans from the `CoverageGraph`. - let Some(coverage_spans) = - mappings::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks) - else { - // No relevant spans were found in MIR, so skip instrumenting this function. - return; - }; + // Extract coverage spans and other mapping info from MIR. + let extracted_mappings = + mappings::extract_all_mapping_info_from_mir(mir_body, &hir_info, &basic_coverage_blocks); //////////////////////////////////////////////////// // Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure // every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock` // and all `Expression` dependencies (operands) are also generated, for any other // `BasicCoverageBlock`s not already associated with a coverage span. - let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb); + let bcbs_with_counter_mappings = + extracted_mappings.all_bcbs_with_counter_mappings(&basic_coverage_blocks); + if bcbs_with_counter_mappings.is_empty() { + // No relevant spans were found in MIR, so skip instrumenting this function. + return; + } + + let bcb_has_counter_mappings = |bcb| bcbs_with_counter_mappings.contains(bcb); let coverage_counters = - CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_coverage_spans); + CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_counter_mappings); - let mappings = create_mappings(tcx, &hir_info, &coverage_spans, &coverage_counters); + let mappings = create_mappings(tcx, &hir_info, &extracted_mappings, &coverage_counters); if mappings.is_empty() { // No spans could be converted into valid mappings, so skip this function. debug!("no spans could be converted into valid mappings; skipping"); @@ -96,13 +100,13 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: inject_coverage_statements( mir_body, &basic_coverage_blocks, - bcb_has_coverage_spans, + bcb_has_counter_mappings, &coverage_counters, ); - inject_mcdc_statements(mir_body, &basic_coverage_blocks, &coverage_spans); + inject_mcdc_statements(mir_body, &basic_coverage_blocks, &extracted_mappings); - let mcdc_num_condition_bitmaps = coverage_spans + let mcdc_num_condition_bitmaps = extracted_mappings .mcdc_decisions .iter() .map(|&mappings::MCDCDecision { decision_depth, .. }| decision_depth) @@ -112,7 +116,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { function_source_hash: hir_info.function_source_hash, num_counters: coverage_counters.num_counters(), - mcdc_bitmap_bytes: coverage_spans.test_vector_bitmap_bytes(), + mcdc_bitmap_bytes: extracted_mappings.mcdc_bitmap_bytes, expressions: coverage_counters.into_expressions(), mappings, mcdc_num_condition_bitmaps, @@ -127,7 +131,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: fn create_mappings<'tcx>( tcx: TyCtxt<'tcx>, hir_info: &ExtractedHirInfo, - coverage_spans: &CoverageSpans, + extracted_mappings: &ExtractedMappings, coverage_counters: &CoverageCounters, ) -> Vec { let source_map = tcx.sess.source_map(); @@ -148,9 +152,18 @@ fn create_mappings<'tcx>( }; let region_for_span = |span: Span| make_code_region(source_map, file_name, span, body_span); + // Fully destructure the mappings struct to make sure we don't miss any kinds. + let ExtractedMappings { + code_mappings, + branch_pairs, + mcdc_bitmap_bytes: _, + mcdc_branches, + mcdc_decisions, + } = extracted_mappings; let mut mappings = Vec::new(); - mappings.extend(coverage_spans.code_mappings.iter().filter_map( + mappings.extend(code_mappings.iter().filter_map( + // Ordinary code mappings are the simplest kind. |&mappings::CodeMapping { span, bcb }| { let code_region = region_for_span(span)?; let kind = MappingKind::Code(term_for_bcb(bcb)); @@ -158,7 +171,7 @@ fn create_mappings<'tcx>( }, )); - mappings.extend(coverage_spans.branch_pairs.iter().filter_map( + mappings.extend(branch_pairs.iter().filter_map( |&mappings::BranchPair { span, true_bcb, false_bcb }| { let true_term = term_for_bcb(true_bcb); let false_term = term_for_bcb(false_bcb); @@ -168,7 +181,7 @@ fn create_mappings<'tcx>( }, )); - mappings.extend(coverage_spans.mcdc_branches.iter().filter_map( + mappings.extend(mcdc_branches.iter().filter_map( |&mappings::MCDCBranch { span, true_bcb, false_bcb, condition_info, decision_depth: _ }| { let code_region = region_for_span(span)?; let true_term = term_for_bcb(true_bcb); @@ -181,7 +194,7 @@ fn create_mappings<'tcx>( }, )); - mappings.extend(coverage_spans.mcdc_decisions.iter().filter_map( + mappings.extend(mcdc_decisions.iter().filter_map( |&mappings::MCDCDecision { span, bitmap_idx, conditions_num, .. }| { let code_region = region_for_span(span)?; let kind = MappingKind::MCDCDecision(DecisionInfo { bitmap_idx, conditions_num }); @@ -249,12 +262,8 @@ fn inject_coverage_statements<'tcx>( fn inject_mcdc_statements<'tcx>( mir_body: &mut mir::Body<'tcx>, basic_coverage_blocks: &CoverageGraph, - coverage_spans: &CoverageSpans, + extracted_mappings: &ExtractedMappings, ) { - if coverage_spans.test_vector_bitmap_bytes() == 0 { - return; - } - // Inject test vector update first because `inject_statement` always insert new statement at head. for &mappings::MCDCDecision { span: _, @@ -262,7 +271,7 @@ fn inject_mcdc_statements<'tcx>( bitmap_idx, conditions_num: _, decision_depth, - } in &coverage_spans.mcdc_decisions + } in &extracted_mappings.mcdc_decisions { for end in end_bcbs { let end_bb = basic_coverage_blocks[*end].leader_bb(); @@ -275,7 +284,7 @@ fn inject_mcdc_statements<'tcx>( } for &mappings::MCDCBranch { span: _, true_bcb, false_bcb, condition_info, decision_depth } in - &coverage_spans.mcdc_branches + &extracted_mappings.mcdc_branches { let Some(condition_info) = condition_info else { continue }; let id = condition_info.condition_id; diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index d0f6ec8f21f84..3019b275fb260 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -202,7 +202,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { if let Some(target_len) = self.map().find_len(target.as_ref()) && let operand_ty = operand.ty(self.local_decls, self.tcx) && let Some(operand_ty) = operand_ty.builtin_deref(true) - && let ty::Array(_, len) = operand_ty.ty.kind() + && let ty::Array(_, len) = operand_ty.kind() && let Some(len) = Const::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env) { state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map()); diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 4dd595ce1e1ce..342d1a1cd5bb0 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -594,7 +594,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let ty = place.ty(self.local_decls, self.tcx).ty; if let Some(Mutability::Not) = ty.ref_mutability() && let Some(pointee_ty) = ty.builtin_deref(true) - && pointee_ty.ty.is_freeze(self.tcx, self.param_env) + && pointee_ty.is_freeze(self.tcx, self.param_env) { // An immutable borrow `_x` always points to the same value for the // lifetime of the borrow, so we can merge all instances of `*_x`. @@ -1133,9 +1133,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { if let Value::Cast { kind, from, to, .. } = self.get(inner) && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize) = kind && let Some(from) = from.builtin_deref(true) - && let ty::Array(_, len) = from.ty.kind() + && let ty::Array(_, len) = from.kind() && let Some(to) = to.builtin_deref(true) - && let ty::Slice(..) = to.ty.kind() + && let ty::Slice(..) = to.kind() { return self.insert_constant(Const::from_ty_const(*len, self.tcx)); } diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs index 8be96b6ba8f28..e407929c9a7fd 100644 --- a/compiler/rustc_mir_transform/src/large_enums.rs +++ b/compiler/rustc_mir_transform/src/large_enums.rs @@ -1,7 +1,7 @@ -use crate::rustc_middle::ty::util::IntTypeExt; use rustc_data_structures::fx::FxHashMap; use rustc_middle::mir::interpret::AllocId; use rustc_middle::mir::*; +use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, AdtDef, ParamEnv, Ty, TyCtxt}; use rustc_session::Session; use rustc_target::abi::{HasDataLayout, Size, TagEncoding, Variants}; diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs index 57b6126dece93..db2bb60bdac34 100644 --- a/compiler/rustc_mir_transform/src/mentioned_items.rs +++ b/compiler/rustc_mir_transform/src/mentioned_items.rs @@ -79,8 +79,8 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> { // add everything that may involve a vtable. let source_ty = operand.ty(self.body, self.tcx); let may_involve_vtable = match ( - source_ty.builtin_deref(true).map(|t| t.ty.kind()), - target_ty.builtin_deref(true).map(|t| t.ty.kind()), + source_ty.builtin_deref(true).map(|t| t.kind()), + target_ty.builtin_deref(true).map(|t| t.kind()), ) { (Some(ty::Array(..)), Some(ty::Str | ty::Slice(..))) => false, // &str/&[T] unsizing _ => true, diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index c26a54616331c..2070895c9002b 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -48,9 +48,9 @@ fn compute_slice_length<'tcx>( let operand_ty = operand.ty(body, tcx); debug!(?operand_ty); if let Some(operand_ty) = operand_ty.builtin_deref(true) - && let ty::Array(_, len) = operand_ty.ty.kind() + && let ty::Array(_, len) = operand_ty.kind() && let Some(cast_ty) = cast_ty.builtin_deref(true) - && let ty::Slice(..) = cast_ty.ty.kind() + && let ty::Slice(..) = cast_ty.kind() { slice_lengths[local] = Some(*len); } diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index cbab200618610..ddfb42a6f4a6c 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -32,10 +32,9 @@ fn custom_coerce_unsize_info<'tcx>( source_ty: Ty<'tcx>, target_ty: Ty<'tcx>, ) -> Result { - let trait_ref = ty::TraitRef::from_lang_item( + let trait_ref = ty::TraitRef::new( tcx.tcx, - LangItem::CoerceUnsized, - tcx.span, + tcx.require_lang_item(LangItem::CoerceUnsized, Some(tcx.span)), [source_ty, target_ty], ); diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index 6d237df073f81..6487169d17398 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -131,7 +131,7 @@ fn mark_used_by_default_parameters<'tcx>( ) { match tcx.def_kind(def_id) { DefKind::Closure => { - for param in &generics.params { + for param in &generics.own_params { debug!(?param, "(closure/gen)"); unused_parameters.mark_used(param.index); } @@ -165,7 +165,7 @@ fn mark_used_by_default_parameters<'tcx>( | DefKind::LifetimeParam | DefKind::GlobalAsm | DefKind::Impl { .. } => { - for param in &generics.params { + for param in &generics.own_params { debug!(?param, "(other)"); if let ty::GenericParamDefKind::Lifetime = param.kind { unused_parameters.mark_used(param.index); @@ -202,7 +202,7 @@ fn emit_unused_generic_params_error<'tcx>( let mut param_names = Vec::new(); let mut next_generics = Some(generics); while let Some(generics) = next_generics { - for param in &generics.params { + for param in &generics.own_params { if unused_parameters.is_unused(param.index) { debug!(?param); let def_span = tcx.def_span(param.def_id); diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 6600b92fb3182..755f5cfa5a378 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -1,11 +1,11 @@ use std::cmp::Ordering; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; -use rustc_type_ir::new::{Const, Region, Ty}; +use rustc_type_ir::inherent::*; use rustc_type_ir::visit::TypeVisitableExt; use rustc_type_ir::{ - self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, ConstTy, - InferCtxtLike, Interner, IntoKind, PlaceholderLike, + self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, InferCtxtLike, + Interner, }; /// Whether we're canonicalizing a query input or the query response. @@ -455,7 +455,7 @@ impl TypeFolder for RegionsToStatic { I::Binder: TypeSuperFoldable, { self.binder.shift_in(1); - let t = t.fold_with(self); + let t = t.super_fold_with(self); self.binder.shift_out(1); t } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 873095dca8722..04f855e4f559b 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -401,10 +401,8 @@ parse_invalid_logical_operator = `{$incorrect}` is not a logical operator .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction -parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}` - -parse_invalid_meta_item_unquoted_ident = expected unsuffixed literal, found `{$token}` - .suggestion = surround the identifier with quotation marks to parse it as a string +parse_invalid_meta_item = expected unsuffixed literal, found `{$token}` + .quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal parse_invalid_offset_of = offset_of expects dot-separated field and variant names diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index d06f03a7c1767..2f68a299f26b6 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -978,21 +978,13 @@ pub(crate) struct InvalidMetaItem { #[primary_span] pub span: Span, pub token: Token, -} - -#[derive(Diagnostic)] -#[diag(parse_invalid_meta_item_unquoted_ident)] -pub(crate) struct InvalidMetaItemUnquotedIdent { - #[primary_span] - pub span: Span, - pub token: Token, #[subdiagnostic] - pub sugg: InvalidMetaItemSuggQuoteIdent, + pub quote_ident_sugg: Option, } #[derive(Subdiagnostic)] -#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")] -pub(crate) struct InvalidMetaItemSuggQuoteIdent { +#[multipart_suggestion(parse_quote_ident_sugg, applicability = "machine-applicable")] +pub(crate) struct InvalidMetaItemQuoteIdentSugg { #[suggestion_part(code = "\"")] pub before: Span, #[suggestion_part(code = "\"")] diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs index 993ff1b97f5e8..1247e2e44fb13 100644 --- a/compiler/rustc_parse/src/lexer/diagnostics.rs +++ b/compiler/rustc_parse/src/lexer/diagnostics.rs @@ -5,7 +5,7 @@ use rustc_span::source_map::SourceMap; use rustc_span::Span; #[derive(Default)] -pub struct TokenTreeDiagInfo { +pub(super) struct TokenTreeDiagInfo { /// Stack of open delimiters and their spans. Used for error message. pub open_braces: Vec<(Delimiter, Span)>, pub unmatched_delims: Vec, @@ -21,7 +21,7 @@ pub struct TokenTreeDiagInfo { pub matching_block_spans: Vec<(Span, Span)>, } -pub fn same_indentation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> bool { +pub(super) fn same_indentation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> bool { match (sm.span_to_margin(open_sp), sm.span_to_margin(close_sp)) { (Some(open_padding), Some(close_padding)) => open_padding == close_padding, _ => false, @@ -30,7 +30,7 @@ pub fn same_indentation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> // When we get a `)` or `]` for `{`, we should emit help message here // it's more friendly compared to report `unmatched error` in later phase -pub fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[UnmatchedDelim]) -> bool { +fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[UnmatchedDelim]) -> bool { let mut reported_missing_open = false; for unmatch_brace in unmatched_delims.iter() { if let Some(delim) = unmatch_brace.found_delim @@ -51,7 +51,7 @@ pub fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[Unmatch reported_missing_open } -pub fn report_suspicious_mismatch_block( +pub(super) fn report_suspicious_mismatch_block( err: &mut Diag<'_>, diag_info: &TokenTreeDiagInfo, sm: &SourceMap, diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 1abb1d29562d9..d2d200a91aff2 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -112,7 +112,7 @@ struct StringReader<'psess, 'src> { } impl<'psess, 'src> StringReader<'psess, 'src> { - pub fn dcx(&self) -> &'psess DiagCtxt { + fn dcx(&self) -> &'psess DiagCtxt { &self.psess.dcx } diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index 6b055fc844ae1..c9470151a7baf 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -9,7 +9,7 @@ use crate::{ use rustc_span::{symbol::kw, BytePos, Pos, Span}; #[rustfmt::skip] // for line breaks -pub(crate) const UNICODE_ARRAY: &[(char, &str, &str)] = &[ +pub(super) const UNICODE_ARRAY: &[(char, &str, &str)] = &[ ('
', "Line Separator", " "), ('
', "Paragraph Separator", " "), (' ', "Ogham Space mark", " "), diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index a46372d368f42..0f973dfcd7969 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -5,6 +5,7 @@ #![allow(rustc::untranslatable_diagnostic)] #![feature(array_windows)] #![feature(box_patterns)] +#![feature(debug_closure_helpers)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(let_chains)] diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index ab5f51eedc307..d5d8060d909a1 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -1,7 +1,4 @@ -use crate::errors::{ - InvalidMetaItem, InvalidMetaItemSuggQuoteIdent, InvalidMetaItemUnquotedIdent, - SuffixedLiteralInAttribute, -}; +use crate::errors; use crate::fluent_generated as fluent; use crate::maybe_whole; @@ -318,7 +315,7 @@ impl<'a> Parser<'a> { debug!("checking if {:?} is unsuffixed", lit); if !lit.kind.is_unsuffixed() { - self.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span }); + self.dcx().emit_err(errors::SuffixedLiteralInAttribute { span: lit.span }); } Ok(lit) @@ -356,10 +353,11 @@ impl<'a> Parser<'a> { Ok(nmis) } - /// Matches the following grammar (per RFC 1559). + /// Parse a meta item per RFC 1559. + /// /// ```ebnf - /// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; - /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; + /// MetaItem = SimplePath ( '=' UNSUFFIXED_LIT | '(' MetaSeq? ')' )? ; + /// MetaSeq = MetaItemInner (',' MetaItemInner)* ','? ; /// ``` pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { // We can't use `maybe_whole` here because it would bump in the `None` @@ -387,7 +385,6 @@ impl<'a> Parser<'a> { Ok(if self.eat(&token::Eq) { ast::MetaItemKind::NameValue(self.parse_unsuffixed_meta_item_lit()?) } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { - // Matches `meta_seq = ( COMMASEP(meta_item_inner) )`. let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?; ast::MetaItemKind::List(list) } else { @@ -395,38 +392,45 @@ impl<'a> Parser<'a> { }) } - /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`. + /// Parse an inner meta item per RFC 1559. + /// + /// ```ebnf + /// MetaItemInner = UNSUFFIXED_LIT | MetaItem ; + /// ``` fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> { match self.parse_unsuffixed_meta_item_lit() { Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)), - Err(err) => err.cancel(), + Err(err) => err.cancel(), // we provide a better error below } match self.parse_meta_item() { Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)), - Err(err) => err.cancel(), + Err(err) => err.cancel(), // we provide a better error below } - let token = self.token.clone(); + let mut err = errors::InvalidMetaItem { + span: self.token.span, + token: self.token.clone(), + quote_ident_sugg: None, + }; - // Check for unquoted idents in meta items, e.g.: #[cfg(key = foo)] - // `from_expansion()` ensures we don't suggest for cases such as - // `#[cfg(feature = $expr)]` in macros - if self.prev_token == token::Eq && !self.token.span.from_expansion() { + // Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and + // don't `uninterpolate` the token to avoid suggesting anything butchered or questionable + // when macro metavariables are involved. + if self.prev_token == token::Eq + && let token::Ident(..) = self.token.kind + { let before = self.token.span.shrink_to_lo(); - while matches!(self.token.kind, token::Ident(..)) { + while let token::Ident(..) = self.token.kind { self.bump(); } - let after = self.prev_token.span.shrink_to_hi(); - let sugg = InvalidMetaItemSuggQuoteIdent { before, after }; - return Err(self.dcx().create_err(InvalidMetaItemUnquotedIdent { - span: token.span, - token, - sugg, - })); + err.quote_ident_sugg = Some(errors::InvalidMetaItemQuoteIdentSugg { + before, + after: self.prev_token.span.shrink_to_hi(), + }); } - Err(self.dcx().create_err(InvalidMetaItem { span: token.span, token })) + Err(self.dcx().create_err(err)) } } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index f256dbf436021..50698dbf9c176 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -22,7 +22,6 @@ use crate::fluent_generated as fluent; use crate::parser; use crate::parser::attr::InnerAttrPolicy; use ast::token::IdentIsRaw; -use parser::Recovered; use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Lit, LitKind, Token, TokenKind}; @@ -31,7 +30,7 @@ use rustc_ast::util::parser::AssocOp; use rustc_ast::{ AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block, BlockCheckMode, Expr, ExprKind, GenericArg, Generics, HasTokens, Item, ItemKind, Param, Pat, - PatKind, Path, PathSegment, QSelf, Ty, TyKind, + PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -527,14 +526,14 @@ impl<'a> Parser<'a> { // // let x = 32: // let y = 42; - self.dcx().emit_err(ExpectedSemi { + let guar = self.dcx().emit_err(ExpectedSemi { span: self.token.span, token: self.token.clone(), unexpected_token_label: None, sugg: ExpectedSemiSugg::ChangeToSemi(self.token.span), }); self.bump(); - return Ok(Recovered::Yes); + return Ok(Recovered::Yes(guar)); } else if self.look_ahead(0, |t| { t == &token::CloseDelim(Delimiter::Brace) || ((t.can_begin_expr() || t.can_begin_item()) @@ -552,13 +551,13 @@ impl<'a> Parser<'a> { // let x = 32 // let y = 42; let span = self.prev_token.span.shrink_to_hi(); - self.dcx().emit_err(ExpectedSemi { + let guar = self.dcx().emit_err(ExpectedSemi { span, token: self.token.clone(), unexpected_token_label: Some(self.token.span), sugg: ExpectedSemiSugg::AddSemi(span), }); - return Ok(Recovered::Yes); + return Ok(Recovered::Yes(guar)); } } @@ -712,8 +711,8 @@ impl<'a> Parser<'a> { if self.check_too_many_raw_str_terminators(&mut err) { if expected.contains(&TokenType::Token(token::Semi)) && self.eat(&token::Semi) { - err.emit(); - return Ok(Recovered::Yes); + let guar = err.emit(); + return Ok(Recovered::Yes(guar)); } else { return Err(err); } @@ -1224,7 +1223,11 @@ impl<'a> Parser<'a> { let x = self.parse_seq_to_before_end( &token::Gt, SeqSep::trailing_allowed(token::Comma), - |p| p.parse_generic_arg(None), + |p| match p.parse_generic_arg(None)? { + Some(arg) => Ok(arg), + // If we didn't eat a generic arg, then we should error. + None => p.unexpected_any(), + }, ); match x { Ok((_, _, Recovered::No)) => { @@ -1251,7 +1254,7 @@ impl<'a> Parser<'a> { } } } - Ok((_, _, Recovered::Yes)) => {} + Ok((_, _, Recovered::Yes(_))) => {} Err(err) => { err.cancel(); } @@ -1284,13 +1287,13 @@ impl<'a> Parser<'a> { /// Check to see if a pair of chained operators looks like an attempt at chained comparison, /// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or - /// parenthesising the leftmost comparison. + /// parenthesising the leftmost comparison. The return value indicates if recovery happened. fn attempt_chained_comparison_suggestion( &mut self, err: &mut ComparisonOperatorsCannotBeChained, inner_op: &Expr, outer_op: &Spanned, - ) -> Recovered { + ) -> bool { if let ExprKind::Binary(op, l1, r1) = &inner_op.kind { if let ExprKind::Field(_, ident) = l1.kind && ident.as_str().parse::().is_err() @@ -1298,7 +1301,7 @@ impl<'a> Parser<'a> { { // The parser has encountered `foo.bar Parser<'a> { span: inner_op.span.shrink_to_hi(), middle_term: expr_to_str(r1), }); - Recovered::No // Keep the current parse behavior, where the AST is `(x < y) < z`. + false // Keep the current parse behavior, where the AST is `(x < y) < z`. } // `x == y < z` (BinOpKind::Eq, AssocOp::Less | AssocOp::LessEqual | AssocOp::Greater | AssocOp::GreaterEqual) => { @@ -1331,12 +1334,12 @@ impl<'a> Parser<'a> { left: r1.span.shrink_to_lo(), right: r2.span.shrink_to_hi(), }); - Recovered::Yes + true } Err(expr_err) => { expr_err.cancel(); self.restore_snapshot(snapshot); - Recovered::Yes + true } } } @@ -1351,19 +1354,19 @@ impl<'a> Parser<'a> { left: l1.span.shrink_to_lo(), right: r1.span.shrink_to_hi(), }); - Recovered::Yes + true } Err(expr_err) => { expr_err.cancel(); self.restore_snapshot(snapshot); - Recovered::No + false } } } - _ => Recovered::No, + _ => false }; } - Recovered::No + false } /// Produces an error if comparison operators are chained (RFC #558). @@ -1494,7 +1497,7 @@ impl<'a> Parser<'a> { // misformatted turbofish, for instance), suggest a correct form. let recovered = self .attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op); - if matches!(recovered, Recovered::Yes) { + if recovered { let guar = self.dcx().emit_err(err); mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar) } else { @@ -1503,10 +1506,10 @@ impl<'a> Parser<'a> { } }; } - let recover = + let recovered = self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op); let guar = self.dcx().emit_err(err); - if matches!(recover, Recovered::Yes) { + if recovered { return mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar); } } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 8ed2a6edf1aec..441aa5b0806da 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3,7 +3,7 @@ use super::diagnostics::SnapshotParser; use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{ - AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Recovered, Restrictions, + AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions, SemiColonMode, SeqSep, TokenExpectType, TokenType, Trailing, TrailingToken, }; @@ -11,7 +11,7 @@ use crate::errors; use crate::maybe_recover_from_interpolated_ty_qpath; use ast::mut_visit::{noop_visit_expr, MutVisitor}; use ast::token::IdentIsRaw; -use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment}; +use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered}; use core::mem; use core::ops::ControlFlow; use rustc_ast::ptr::P; @@ -497,8 +497,7 @@ impl<'a> Parser<'a> { /// Checks if this expression is a successfully parsed statement. fn expr_is_complete(&self, e: &Expr) -> bool { - self.restrictions.contains(Restrictions::STMT_EXPR) - && !classify::expr_requires_semi_to_be_stmt(e) + self.restrictions.contains(Restrictions::STMT_EXPR) && classify::expr_is_complete(e) } /// Parses `x..y`, `x..=y`, and `x..`/`x..=`. @@ -2629,7 +2628,7 @@ impl<'a> Parser<'a> { CondChecker::new(self).visit_expr(&mut cond); - if let ExprKind::Let(_, _, _, None) = cond.kind { + if let ExprKind::Let(_, _, _, Recovered::No) = cond.kind { // Remove the last feature gating of a `let` expression since it's stable. self.psess.gated_spans.ungate_last(sym::let_chains, cond.span); } @@ -2639,7 +2638,7 @@ impl<'a> Parser<'a> { /// Parses a `let $pat = $expr` pseudo-expression. fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, P> { - let is_recovered = if !restrictions.contains(Restrictions::ALLOW_LET) { + let recovered = if !restrictions.contains(Restrictions::ALLOW_LET) { let err = errors::ExpectedExpressionFoundLet { span: self.token.span, reason: ForbiddenLetReason::OtherForbidden, @@ -2650,10 +2649,10 @@ impl<'a> Parser<'a> { // This was part of a closure, the that part of the parser recover. return Err(self.dcx().create_err(err)); } else { - Some(self.dcx().emit_err(err)) + Recovered::Yes(self.dcx().emit_err(err)) } } else { - None + Recovered::No }; self.bump(); // Eat `let` token let lo = self.prev_token.span; @@ -2674,7 +2673,7 @@ impl<'a> Parser<'a> { } let expr = self.parse_expr_assoc_with(1 + prec_let_scrutinee_needs_par(), None.into())?; let span = lo.to(expr.span); - Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span, is_recovered))) + Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span, recovered))) } /// Parses an `else { ... }` expression (`else` token already eaten). @@ -2691,8 +2690,33 @@ impl<'a> Parser<'a> { let first_tok_span = self.token.span; match self.parse_expr() { Ok(cond) - // If it's not a free-standing expression, and is followed by a block, - // then it's very likely the condition to an `else if`. + // Try to guess the difference between a "condition-like" vs + // "statement-like" expression. + // + // We are seeing the following code, in which $cond is neither + // ExprKind::Block nor ExprKind::If (the 2 cases wherein this + // would be valid syntax). + // + // if ... { + // } else $cond + // + // If $cond is "condition-like" such as ExprKind::Binary, we + // want to suggest inserting `if`. + // + // if ... { + // } else if a == b { + // ^^ + // } + // + // If $cond is "statement-like" such as ExprKind::While then we + // want to suggest wrapping in braces. + // + // if ... { + // } else { + // ^ + // while true {} + // } + // ^ if self.check(&TokenKind::OpenDelim(Delimiter::Brace)) && classify::expr_requires_semi_to_be_stmt(&cond) => { @@ -2998,7 +3022,7 @@ impl<'a> Parser<'a> { &mut self, first_expr: &P, arrow_span: Span, - ) -> Option> { + ) -> Option<(Span, ErrorGuaranteed)> { if self.token.kind != token::Semi { return None; } @@ -3023,7 +3047,7 @@ impl<'a> Parser<'a> { errors::MatchArmBodyWithoutBracesSugg::UseComma { semicolon: semi_sp } }, }); - this.mk_expr_err(span, guar) + (span, guar) }; // We might have either a `,` -> `;` typo, or a block without braces. We need // a more subtle parsing strategy. @@ -3136,16 +3160,19 @@ impl<'a> Parser<'a> { err })?; - let require_comma = classify::expr_requires_semi_to_be_stmt(&expr) + let require_comma = !classify::expr_is_complete(&expr) && this.token != token::CloseDelim(Delimiter::Brace); if !require_comma { arm_body = Some(expr); this.eat(&token::Comma); Ok(Recovered::No) - } else if let Some(body) = this.parse_arm_body_missing_braces(&expr, arrow_span) { + } else if let Some((span, guar)) = + this.parse_arm_body_missing_braces(&expr, arrow_span) + { + let body = this.mk_expr_err(span, guar); arm_body = Some(body); - Ok(Recovered::Yes) + Ok(Recovered::Yes(guar)) } else { let expr_span = expr.span; arm_body = Some(expr); @@ -3223,10 +3250,10 @@ impl<'a> Parser<'a> { .is_ok(); if pattern_follows && snapshot.check(&TokenKind::FatArrow) { err.cancel(); - this.dcx().emit_err(errors::MissingCommaAfterMatchArm { + let guar = this.dcx().emit_err(errors::MissingCommaAfterMatchArm { span: arm_span.shrink_to_hi(), }); - return Ok(Recovered::Yes); + return Ok(Recovered::Yes(guar)); } Err(err) }); @@ -3904,15 +3931,16 @@ impl MutVisitor for CondChecker<'_> { let span = e.span; match e.kind { - ExprKind::Let(_, _, _, ref mut is_recovered @ None) => { + ExprKind::Let(_, _, _, ref mut recovered @ Recovered::No) => { if let Some(reason) = self.forbid_let_reason { - *is_recovered = - Some(self.parser.dcx().emit_err(errors::ExpectedExpressionFoundLet { + *recovered = Recovered::Yes(self.parser.dcx().emit_err( + errors::ExpectedExpressionFoundLet { span, reason, missing_let: self.missing_let, comparison: self.comparison, - })); + }, + )); } else { self.parser.psess.gated_spans.gate(sym::let_chains, span); } @@ -3980,7 +4008,7 @@ impl MutVisitor for CondChecker<'_> { self.visit_expr(op); self.forbid_let_reason = forbid_let_reason; } - ExprKind::Let(_, _, _, Some(_)) + ExprKind::Let(_, _, _, Recovered::Yes(_)) | ExprKind::Array(_) | ExprKind::ConstBlock(_) | ExprKind::Lit(_) diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 848277c4611e3..df6996dbc458b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1,8 +1,7 @@ use super::diagnostics::{dummy_arg, ConsumeClosingDelim}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{ - AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Recovered, Trailing, - TrailingToken, + AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Trailing, TrailingToken, }; use crate::errors::{self, MacroExpandsToAdtField}; use crate::fluent_generated as fluent; @@ -336,7 +335,7 @@ impl<'a> Parser<'a> { UseTreeKind::Glob => { e.note("the wildcard token must be last on the path"); } - UseTreeKind::Nested(..) => { + UseTreeKind::Nested { .. } => { e.note("glob-like brace syntax must be last on the path"); } _ => (), @@ -1056,7 +1055,11 @@ impl<'a> Parser<'a> { Ok(if self.eat(&token::BinOp(token::Star)) { UseTreeKind::Glob } else { - UseTreeKind::Nested(self.parse_use_tree_list()?) + let lo = self.token.span; + UseTreeKind::Nested { + items: self.parse_use_tree_list()?, + span: lo.to(self.prev_token.span), + } }) } @@ -1536,8 +1539,8 @@ impl<'a> Parser<'a> { this.bump(); // } err.span_label(span, "while parsing this enum"); err.help(help); - err.emit(); - (thin_vec![], Recovered::Yes) + let guar = err.emit(); + (thin_vec![], Recovered::Yes(guar)) } }; VariantData::Struct { fields, recovered: recovered.into() } @@ -1695,16 +1698,15 @@ impl<'a> Parser<'a> { let mut recovered = Recovered::No; if self.eat(&token::OpenDelim(Delimiter::Brace)) { while self.token != token::CloseDelim(Delimiter::Brace) { - let field = self.parse_field_def(adt_ty).map_err(|e| { - self.consume_block(Delimiter::Brace, ConsumeClosingDelim::No); - recovered = Recovered::Yes; - e - }); - match field { - Ok(field) => fields.push(field), + match self.parse_field_def(adt_ty) { + Ok(field) => { + fields.push(field); + } Err(mut err) => { + self.consume_block(Delimiter::Brace, ConsumeClosingDelim::No); err.span_label(ident_span, format!("while parsing this {adt_ty}")); - err.emit(); + let guar = err.emit(); + recovered = Recovered::Yes(guar); break; } } @@ -2465,7 +2467,7 @@ impl<'a> Parser<'a> { // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't // account for this. match self.expect_one_of(&[], &[]) { - Ok(Recovered::Yes) => {} + Ok(Recovered::Yes(_)) => {} Ok(Recovered::No) => unreachable!(), Err(mut err) => { // Qualifier keywords ordering check diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index f1476fe02c5f6..bfb6c4a38858e 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -19,6 +19,7 @@ pub(crate) use item::FnParseMode; pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; pub use path::PathStyle; +use core::fmt; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing}; @@ -26,13 +27,12 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor}; use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, AnonConst, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, DelimArgs, - Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, StrLit, Unsafe, Visibility, + Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, StrLit, Unsafe, Visibility, VisibilityKind, DUMMY_NODE_ID, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::PResult; -use rustc_errors::{Applicability, Diag, FatalError, MultiSpan}; +use rustc_errors::{Applicability, Diag, FatalError, MultiSpan, PResult}; use rustc_session::parse::ParseSess; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -60,7 +60,7 @@ mod mut_visit { } bitflags::bitflags! { - #[derive(Clone, Copy)] + #[derive(Clone, Copy, Debug)] struct Restrictions: u8 { const STMT_EXPR = 1 << 0; const NO_STRUCT_LITERAL = 1 << 1; @@ -86,7 +86,7 @@ enum BlockMode { /// Whether or not we should force collection of tokens for an AST node, /// regardless of whether or not it has attributes -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum ForceCollect { Yes, No, @@ -134,7 +134,7 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath { }; } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum Recovery { Allowed, Forbidden, @@ -184,7 +184,7 @@ pub struct Parser<'a> { capture_state: CaptureState, /// This allows us to recover when the user forget to add braces around /// multiple statements in the closure body. - pub current_closure: Option, + current_closure: Option, /// Whether the parser is allowed to do recovery. /// This is disabled when parsing macro arguments, see #103534 pub recovery: Recovery, @@ -196,7 +196,7 @@ pub struct Parser<'a> { rustc_data_structures::static_assert_size!(Parser<'_>, 264); /// Stores span information about a closure. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct ClosureSpans { pub whole_closure: Span, pub closing_pipe: Span, @@ -225,7 +225,7 @@ pub type ReplaceRange = (Range, Vec<(FlatToken, Spacing)>); /// Controls how we capture tokens. Capturing can be expensive, /// so we try to avoid performing capturing in cases where /// we will never need an `AttrTokenStream`. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub enum Capturing { /// We aren't performing any capturing - this is the default mode. No, @@ -233,7 +233,7 @@ pub enum Capturing { Yes, } -#[derive(Clone)] +#[derive(Clone, Debug)] struct CaptureState { capturing: Capturing, replace_ranges: Vec, @@ -244,7 +244,7 @@ struct CaptureState { /// we (a) lex tokens into a nice tree structure (`TokenStream`), and then (b) /// use this type to emit them as a linear sequence. But a linear sequence is /// what the parser expects, for the most part. -#[derive(Clone)] +#[derive(Clone, Debug)] struct TokenCursor { // Cursor for the current (innermost) token stream. The delimiters for this // token stream are found in `self.stack.last()`; when that is `None` then @@ -349,6 +349,7 @@ enum TokenExpectType { } /// A sequence separator. +#[derive(Debug)] struct SeqSep { /// The separator token. sep: Option, @@ -366,31 +367,19 @@ impl SeqSep { } } +#[derive(Debug)] pub enum FollowedByType { Yes, No, } -/// Whether a function performed recovery -#[derive(Copy, Clone, Debug)] -pub enum Recovered { - No, - Yes, -} - -impl From for bool { - fn from(r: Recovered) -> bool { - matches!(r, Recovered::Yes) - } -} - #[derive(Copy, Clone, Debug)] pub enum Trailing { No, Yes, } -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum TokenDescription { ReservedIdentifier, Keyword, @@ -853,9 +842,9 @@ impl<'a> Parser<'a> { Ok(Recovered::No) => { self.current_closure.take(); } - Ok(Recovered::Yes) => { + Ok(Recovered::Yes(guar)) => { self.current_closure.take(); - recovered = Recovered::Yes; + recovered = Recovered::Yes(guar); break; } Err(mut expect_err) => { @@ -1548,6 +1537,47 @@ impl<'a> Parser<'a> { }) } + // debug view of the parser's token stream, up to `{lookahead}` tokens + pub fn debug_lookahead(&self, lookahead: usize) -> impl fmt::Debug + '_ { + struct DebugParser<'dbg> { + parser: &'dbg Parser<'dbg>, + lookahead: usize, + } + + impl fmt::Debug for DebugParser<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { parser, lookahead } = self; + let mut dbg_fmt = f.debug_struct("Parser"); // or at least, one view of + + // we don't need N spans, but we want at least one, so print all of prev_token + dbg_fmt.field("prev_token", &parser.prev_token); + // make it easier to peek farther ahead by taking TokenKinds only until EOF + let tokens = (0..*lookahead) + .map(|i| parser.look_ahead(i, |tok| tok.kind.clone())) + .scan(parser.prev_token == TokenKind::Eof, |eof, tok| { + let current = eof.then_some(tok.clone()); // include a trailing EOF token + *eof |= &tok == &TokenKind::Eof; + current + }); + dbg_fmt.field_with("tokens", |field| field.debug_list().entries(tokens).finish()); + dbg_fmt.field("approx_token_stream_pos", &parser.num_bump_calls); + + // some fields are interesting for certain values, as they relate to macro parsing + if let Some(subparser) = parser.subparser_name { + dbg_fmt.field("subparser_name", &subparser); + } + if let Recovery::Forbidden = parser.recovery { + dbg_fmt.field("recovery", &parser.recovery); + } + + // imply there's "more to know" than this view + dbg_fmt.finish_non_exhaustive() + } + } + + DebugParser { parser: self, lookahead } + } + pub fn clear_expected_tokens(&mut self) { self.expected_tokens.clear(); } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index b97ec8c613d91..3636a3579781b 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -160,7 +160,7 @@ impl<'a> Parser<'a> { style: PathStyle, ty_generics: Option<&Generics>, ) -> PResult<'a, Path> { - let reject_generics_if_mod_style = |parser: &Parser<'_>, path: &Path| { + let reject_generics_if_mod_style = |parser: &Parser<'_>, path: Path| { // Ensure generic arguments don't end up in attribute paths, such as: // // macro_rules! m { @@ -178,21 +178,26 @@ impl<'a> Parser<'a> { .map(|arg| arg.span()) .collect::>(); parser.dcx().emit_err(errors::GenericsInPath { span }); + // Ignore these arguments to prevent unexpected behaviors. + let segments = path + .segments + .iter() + .map(|segment| PathSegment { ident: segment.ident, id: segment.id, args: None }) + .collect(); + Path { segments, ..path } + } else { + path } }; - maybe_whole!(self, NtPath, |path| { - reject_generics_if_mod_style(self, &path); - path.into_inner() - }); + maybe_whole!(self, NtPath, |path| reject_generics_if_mod_style(self, path.into_inner())); if let token::Interpolated(nt) = &self.token.kind { if let token::NtTy(ty) = &nt.0 { if let ast::TyKind::Path(None, path) = &ty.kind { let path = path.clone(); self.bump(); - reject_generics_if_mod_style(self, &path); - return Ok(path); + return Ok(reject_generics_if_mod_style(self, path)); } } } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 6601011665b41..d70afebf1b2da 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -11,14 +11,13 @@ use crate::errors; use crate::maybe_whole; use crate::errors::MalformedLoopLabel; -use crate::parser::Recovered; use ast::Label; use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, TokenKind}; use rustc_ast::util::classify; use rustc_ast::{AttrStyle, AttrVec, LocalKind, MacCall, MacCallStmt, MacStmtStyle}; -use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Stmt}; +use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Recovered, Stmt}; use rustc_ast::{StmtKind, DUMMY_NODE_ID}; use rustc_errors::{Applicability, Diag, PResult}; use rustc_span::symbol::{kw, sym, Ident}; @@ -675,11 +674,8 @@ impl<'a> Parser<'a> { let replace_with_err = 'break_recover: { match expect_result { Ok(Recovered::No) => None, - Ok(Recovered::Yes) => { + Ok(Recovered::Yes(guar)) => { // Skip type error to avoid extra errors. - let guar = self - .dcx() - .span_delayed_bug(self.prev_token.span, "expected `;` or `}`"); Some(guar) } Err(e) => { diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 9d58d301e2bc2..3deefcaa06c3d 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -52,16 +52,16 @@ passes_attr_only_in_functions = passes_both_ffi_const_and_pure = `#[ffi_const]` function cannot be `#[ffi_pure]` -passes_break_inside_async_block = - `{$name}` inside of an `async` block - .label = cannot `{$name}` inside of an `async` block - .async_block_label = enclosing `async` block - passes_break_inside_closure = `{$name}` inside of a closure .label = cannot `{$name}` inside of a closure .closure_label = enclosing closure +passes_break_inside_coroutine = + `{$name}` inside `{$kind}` {$source} + .label = cannot `{$name}` inside `{$kind}` {$source} + .coroutine_label = enclosing `{$kind}` {$source} + passes_break_non_loop = `break` with value from a `{$kind}` loop .label = can only break with a value inside `loop` or breakable block diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 65cad82cc8c2b..b8586e7e974ad 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1086,14 +1086,16 @@ pub struct BreakInsideClosure<'a> { } #[derive(Diagnostic)] -#[diag(passes_break_inside_async_block, code = E0267)] -pub struct BreakInsideAsyncBlock<'a> { +#[diag(passes_break_inside_coroutine, code = E0267)] +pub struct BreakInsideCoroutine<'a> { #[primary_span] #[label] pub span: Span, - #[label(passes_async_block_label)] - pub closure_span: Span, + #[label(passes_coroutine_label)] + pub coroutine_span: Span, pub name: &'a str, + pub kind: &'a str, + pub source: &'a str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 4b5c4dfe991b7..3b20112eab7b9 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -13,7 +13,7 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::{BytePos, Span}; use crate::errors::{ - BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop, + BreakInsideClosure, BreakInsideCoroutine, BreakNonLoop, ContinueLabeledBlock, OutsideLoop, OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock, }; @@ -23,7 +23,7 @@ enum Context { Fn, Loop(hir::LoopSource), Closure(Span), - AsyncClosure(Span), + Coroutine { coroutine_span: Span, kind: hir::CoroutineDesugaring, source: hir::CoroutineSource }, UnlabeledBlock(Span), LabeledBlock, Constant, @@ -89,12 +89,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { hir::ExprKind::Closure(&hir::Closure { ref fn_decl, body, fn_decl_span, kind, .. }) => { - // FIXME(coroutines): This doesn't handle coroutines correctly let cx = match kind { - hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( - hir::CoroutineDesugaring::Async, - hir::CoroutineSource::Block, - )) => AsyncClosure(fn_decl_span), + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(kind, source)) => { + Coroutine { coroutine_span: fn_decl_span, kind, source } + } _ => Closure(fn_decl_span), }; self.visit_fn_decl(fn_decl); @@ -227,8 +225,24 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> { Closure(closure_span) => { self.sess.dcx().emit_err(BreakInsideClosure { span, closure_span, name }); } - AsyncClosure(closure_span) => { - self.sess.dcx().emit_err(BreakInsideAsyncBlock { span, closure_span, name }); + Coroutine { coroutine_span, kind, source } => { + let kind = match kind { + hir::CoroutineDesugaring::Async => "async", + hir::CoroutineDesugaring::Gen => "gen", + hir::CoroutineDesugaring::AsyncGen => "async gen", + }; + let source = match source { + hir::CoroutineSource::Block => "block", + hir::CoroutineSource::Closure => "closure", + hir::CoroutineSource::Fn => "function", + }; + self.sess.dcx().emit_err(BreakInsideCoroutine { + span, + coroutine_span, + name, + kind, + source, + }); } UnlabeledBlock(block_span) if is_break && block_span.eq_ctxt(break_span) => { let suggestion = Some(OutsideLoopSuggestion { block_span, break_span }); diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index d5e1a70fd45c4..55b7c6dce4d9b 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -1,14 +1,26 @@ -//! Finds local items that are externally reachable, which means that other crates need access to -//! their compiled machine code or their MIR. +//! Finds local items that are "reachable", which means that other crates need access to their +//! compiled code or their *runtime* MIR. (Compile-time MIR is always encoded anyway, so we don't +//! worry about that here.) //! -//! An item is "externally reachable" if it is relevant for other crates. This obviously includes -//! all public items. However, some of these items cannot be compiled to machine code (because they -//! are generic), and for some the machine code is not sufficient (because we want to cross-crate -//! inline them). These items "need cross-crate MIR". When a reachable function `f` needs -//! cross-crate MIR, then all the functions it calls also become reachable, as they will be -//! necessary to use the MIR of `f` from another crate. Furthermore, an item can become "externally -//! reachable" by having a `const`/`const fn` return a pointer to that item, so we also need to -//! recurse into reachable `const`/`const fn`. +//! An item is "reachable" if codegen that happens in downstream crates can end up referencing this +//! item. This obviously includes all public items. However, some of these items cannot be codegen'd +//! (because they are generic), and for some the compiled code is not sufficient (because we want to +//! cross-crate inline them). These items "need cross-crate MIR". When a reachable function `f` +//! needs cross-crate MIR, then its MIR may be codegen'd in a downstream crate, and hence items it +//! mentions need to be considered reachable. +//! +//! Furthermore, if a `const`/`const fn` is reachable, then it can return pointers to other items, +//! making those reachable as well. For instance, consider a `const fn` returning a pointer to an +//! otherwise entirely private function: if a downstream crate calls that `const fn` to compute the +//! initial value of a `static`, then it needs to generate a direct reference to this function -- +//! i.e., the function is directly reachable from that downstream crate! Hence we have to recurse +//! into `const` and `const fn`. +//! +//! Conversely, reachability *stops* when it hits a monomorphic non-`const` function that we do not +//! want to cross-crate inline. That function will just be codegen'd in this crate, which means the +//! monomorphization collector will consider it a root and then do another graph traversal to +//! codegen everything called by this function -- but that's a very different graph from what we are +//! considering here as at that point, everything is monomorphic. use hir::def_id::LocalDefIdSet; use rustc_data_structures::stack::ensure_sufficient_stack; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index a78f7e65981ab..c8143015583ef 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -20,6 +20,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AssocItemKind, ForeignItemKind, ItemId, ItemKind, PatKind}; use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level}; use rustc_middle::query::Providers; +use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::GenericArgs; use rustc_middle::ty::{self, Const, GenericParamDefKind}; use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; @@ -787,7 +788,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { impl ReachEverythingInTheInterfaceVisitor<'_, '_> { fn generics(&mut self) -> &mut Self { - for param in &self.ev.tcx.generics_of(self.item_def_id).params { + for param in &self.ev.tcx.generics_of(self.item_def_id).own_params { match param.kind { GenericParamDefKind::Lifetime => {} GenericParamDefKind::Type { has_default, .. } => { @@ -1259,7 +1260,7 @@ struct SearchInterfaceForPrivateItemsVisitor<'tcx> { impl SearchInterfaceForPrivateItemsVisitor<'_> { fn generics(&mut self) -> &mut Self { self.in_primary_interface = true; - for param in &self.tcx.generics_of(self.item_def_id).params { + for param in &self.tcx.generics_of(self.item_def_id).own_params { match param.kind { GenericParamDefKind::Lifetime => {} GenericParamDefKind::Type { has_default, .. } => { diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index aa9657797310c..a7696b1fbaff4 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -2,8 +2,6 @@ //! generate the actual methods on tcx which find and execute the provider, //! manage the caches, and so forth. -use crate::rustc_middle::dep_graph::DepContext; -use crate::rustc_middle::ty::TyEncoder; use crate::QueryConfigRestored; use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_data_structures::sync::Lock; @@ -13,14 +11,14 @@ use rustc_errors::DiagInner; use rustc_index::Idx; use rustc_middle::dep_graph::dep_kinds; use rustc_middle::dep_graph::{ - self, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex, + self, DepContext, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex, }; use rustc_middle::query::on_disk_cache::AbsoluteBytePos; use rustc_middle::query::on_disk_cache::{CacheDecoder, CacheEncoder, EncodedDepNodeIndex}; use rustc_middle::query::Key; use rustc_middle::ty::print::with_reduced_queries; use rustc_middle::ty::tls::{self, ImplicitCtxt}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt, TyEncoder}; use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext}; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{ diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 8068ea1a40773..3467f1c3edfda 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -560,7 +560,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis); } - ast::UseTreeKind::Nested(ref items) => { + ast::UseTreeKind::Nested { ref items, .. } => { // Ensure there is at most one `self` in the list let self_spans = items .iter() diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index f6004fed8284e..5fe68085d6537 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -128,7 +128,7 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> { self.unused_import(self.base_id).add(id); } } - ast::UseTreeKind::Nested(ref items) => self.check_imports_as_underscore(items), + ast::UseTreeKind::Nested { ref items, .. } => self.check_imports_as_underscore(items), _ => {} } } @@ -254,7 +254,7 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> { return; } - if let ast::UseTreeKind::Nested(ref items) = use_tree.kind { + if let ast::UseTreeKind::Nested { ref items, .. } = use_tree.kind { if items.is_empty() { self.unused_import(self.base_id).add(id); } @@ -268,9 +268,8 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> { enum UnusedSpanResult { Used, - FlatUnused(Span, Span), - NestedFullUnused(Vec, Span), - NestedPartialUnused(Vec, Vec), + Unused { spans: Vec, remove: Span }, + PartialUnused { spans: Vec, remove: Vec }, } fn calc_unused_spans( @@ -288,36 +287,33 @@ fn calc_unused_spans( match use_tree.kind { ast::UseTreeKind::Simple(..) | ast::UseTreeKind::Glob => { if unused_import.unused.contains(&use_tree_id) { - UnusedSpanResult::FlatUnused(use_tree.span, full_span) + UnusedSpanResult::Unused { spans: vec![use_tree.span], remove: full_span } } else { UnusedSpanResult::Used } } - ast::UseTreeKind::Nested(ref nested) => { + ast::UseTreeKind::Nested { items: ref nested, span: tree_span } => { if nested.is_empty() { - return UnusedSpanResult::FlatUnused(use_tree.span, full_span); + return UnusedSpanResult::Unused { spans: vec![use_tree.span], remove: full_span }; } let mut unused_spans = Vec::new(); let mut to_remove = Vec::new(); - let mut all_nested_unused = true; + let mut used_childs = 0; + let mut contains_self = false; let mut previous_unused = false; for (pos, (use_tree, use_tree_id)) in nested.iter().enumerate() { let remove = match calc_unused_spans(unused_import, use_tree, *use_tree_id) { UnusedSpanResult::Used => { - all_nested_unused = false; + used_childs += 1; None } - UnusedSpanResult::FlatUnused(span, remove) => { - unused_spans.push(span); - Some(remove) - } - UnusedSpanResult::NestedFullUnused(mut spans, remove) => { + UnusedSpanResult::Unused { mut spans, remove } => { unused_spans.append(&mut spans); Some(remove) } - UnusedSpanResult::NestedPartialUnused(mut spans, mut to_remove_extra) => { - all_nested_unused = false; + UnusedSpanResult::PartialUnused { mut spans, remove: mut to_remove_extra } => { + used_childs += 1; unused_spans.append(&mut spans); to_remove.append(&mut to_remove_extra); None @@ -326,7 +322,7 @@ fn calc_unused_spans( if let Some(remove) = remove { let remove_span = if nested.len() == 1 { remove - } else if pos == nested.len() - 1 || !all_nested_unused { + } else if pos == nested.len() - 1 || used_childs > 0 { // Delete everything from the end of the last import, to delete the // previous comma nested[pos - 1].0.span.shrink_to_hi().to(use_tree.span) @@ -344,14 +340,38 @@ fn calc_unused_spans( to_remove.push(remove_span); } } + contains_self |= use_tree.prefix == kw::SelfLower + && matches!(use_tree.kind, ast::UseTreeKind::Simple(None)); previous_unused = remove.is_some(); } if unused_spans.is_empty() { UnusedSpanResult::Used - } else if all_nested_unused { - UnusedSpanResult::NestedFullUnused(unused_spans, full_span) + } else if used_childs == 0 { + UnusedSpanResult::Unused { spans: unused_spans, remove: full_span } } else { - UnusedSpanResult::NestedPartialUnused(unused_spans, to_remove) + // If there is only one remaining child that is used, the braces around the use + // tree are not needed anymore. In that case, we determine the span of the left + // brace and the right brace, and tell rustfix to remove them as well. + // + // This means that `use a::{B, C};` will be turned into `use a::B;` rather than + // `use a::{B};`, removing a rustfmt roundtrip. + // + // Note that we cannot remove the braces if the only item inside the use tree is + // `self`: `use foo::{self};` is valid Rust syntax, while `use foo::self;` errors + // out. We also cannot turn `use foo::{self}` into `use foo`, as the former doesn't + // import types with the same name as the module. + if used_childs == 1 && !contains_self { + // Left brace, from the start of the nested group to the first item. + to_remove.push( + tree_span.shrink_to_lo().to(nested.first().unwrap().0.span.shrink_to_lo()), + ); + // Right brace, from the end of the last item to the end of the nested group. + to_remove.push( + nested.last().unwrap().0.span.shrink_to_hi().to(tree_span.shrink_to_hi()), + ); + } + + UnusedSpanResult::PartialUnused { spans: unused_spans, remove: to_remove } } } } @@ -417,15 +437,11 @@ impl Resolver<'_, '_> { let mut fixes = Vec::new(); let spans = match calc_unused_spans(unused, &unused.use_tree, unused.use_tree_id) { UnusedSpanResult::Used => continue, - UnusedSpanResult::FlatUnused(span, remove) => { - fixes.push((remove, String::new())); - vec![span] - } - UnusedSpanResult::NestedFullUnused(spans, remove) => { + UnusedSpanResult::Unused { spans, remove } => { fixes.push((remove, String::new())); spans } - UnusedSpanResult::NestedPartialUnused(spans, remove) => { + UnusedSpanResult::PartialUnused { spans, remove } => { for fix in &remove { fixes.push((*fix, String::new())); } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 6c870ddfd227a..5dd95a1896bb1 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2347,8 +2347,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { None => {} } } - } else if let UseTreeKind::Nested(use_trees) = &use_tree.kind { - for (use_tree, _) in use_trees { + } else if let UseTreeKind::Nested { items, .. } = &use_tree.kind { + for (use_tree, _) in items { self.future_proof_import(use_tree); } } @@ -2525,7 +2525,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ItemKind::Use(ref use_tree) => { let maybe_exported = match use_tree.kind { UseTreeKind::Simple(_) | UseTreeKind::Glob => MaybeExported::Ok(item.id), - UseTreeKind::Nested(_) => MaybeExported::NestedUse(&item.vis), + UseTreeKind::Nested { .. } => MaybeExported::NestedUse(&item.vis), }; self.resolve_doc_links(&item.attrs, maybe_exported); diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 7141c6c9bb0c3..21433cfdb613e 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -8,7 +8,8 @@ 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, + self, ExistentialPredicateStableCmpExt as _, Instance, IntTy, List, Ty, TyCtxt, TypeFoldable, + TypeVisitableExt, UintTy, }; use rustc_span::sym; use rustc_trait_selection::traits; diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 6fb1560ac6c10..cbc3aae1703ea 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -256,10 +256,9 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Primitive { rustc_abi::Primitive::Int(length, signed) => { Primitive::Int { length: length.stable(tables), signed: *signed } } - rustc_abi::Primitive::F16 => Primitive::Float { length: FloatLength::F16 }, - rustc_abi::Primitive::F32 => Primitive::Float { length: FloatLength::F32 }, - rustc_abi::Primitive::F64 => Primitive::Float { length: FloatLength::F64 }, - rustc_abi::Primitive::F128 => Primitive::Float { length: FloatLength::F128 }, + rustc_abi::Primitive::Float(length) => { + Primitive::Float { length: length.stable(tables) } + } rustc_abi::Primitive::Pointer(space) => Primitive::Pointer(space.stable(tables)), } } @@ -287,6 +286,19 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Integer { } } +impl<'tcx> Stable<'tcx> for rustc_abi::Float { + type T = FloatLength; + + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { + match self { + rustc_abi::Float::F16 => FloatLength::F16, + rustc_abi::Float::F32 => FloatLength::F32, + rustc_abi::Float::F64 => FloatLength::F64, + rustc_abi::Float::F128 => FloatLength::F128, + } + } +} + impl<'tcx> Stable<'tcx> for rustc_abi::WrappingRange { type T = WrappingRange; diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 4abf991fba25d..c442d33cf8660 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -523,7 +523,7 @@ impl<'tcx> Stable<'tcx> for ty::Generics { fn stable(&self, tables: &mut Tables<'_>) -> Self::T { use stable_mir::ty::Generics; - let params: Vec<_> = self.params.iter().map(|param| param.stable(tables)).collect(); + let params: Vec<_> = self.own_params.iter().map(|param| param.stable(tables)).collect(); let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect(); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 5cdfb773b5cb6..1de2ecbb7006d 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -630,8 +630,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { let pointee_ty = ct .ty() .builtin_deref(true) - .expect("tried to dereference on non-ptr type") - .ty; + .expect("tried to dereference on non-ptr type"); // FIXME(const_generics): add an assert that we only do this for valtrees. let dereferenced_const = self.tcx.mk_ct_from_kind(ct.kind(), pointee_ty); dereferenced_const.print(self)?; diff --git a/compiler/rustc_target/src/abi/call/loongarch.rs b/compiler/rustc_target/src/abi/call/loongarch.rs index 943b12a9fbfcc..893818af77c30 100644 --- a/compiler/rustc_target/src/abi/call/loongarch.rs +++ b/compiler/rustc_target/src/abi/call/loongarch.rs @@ -59,7 +59,7 @@ where _ => return Err(CannotUseFpConv), } } - abi::F16 | abi::F32 | abi::F64 | abi::F128 => { + abi::Float(_) => { if arg_layout.size.bits() > flen { return Err(CannotUseFpConv); } diff --git a/compiler/rustc_target/src/abi/call/mips64.rs b/compiler/rustc_target/src/abi/call/mips64.rs index b2a2c34b980f6..5b52ebbdedd1a 100644 --- a/compiler/rustc_target/src/abi/call/mips64.rs +++ b/compiler/rustc_target/src/abi/call/mips64.rs @@ -26,8 +26,8 @@ where { match ret.layout.field(cx, i).abi { abi::Abi::Scalar(scalar) => match scalar.primitive() { - abi::F32 => Some(Reg::f32()), - abi::F64 => Some(Reg::f64()), + abi::Float(abi::F32) => Some(Reg::f32()), + abi::Float(abi::F64) => Some(Reg::f64()), _ => None, }, _ => None, @@ -110,7 +110,7 @@ where // We only care about aligned doubles if let abi::Abi::Scalar(scalar) = field.abi { - if let abi::F64 = scalar.primitive() { + if scalar.primitive() == abi::Float(abi::F64) { if offset.is_aligned(dl.f64_align.abi) { // Insert enough integers to cover [last_offset, offset) assert!(last_offset.is_aligned(dl.f64_align.abi)); diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 3ddea42f67bbd..919fa2140d5be 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -443,7 +443,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Abi::Scalar(scalar) => { let kind = match scalar.primitive() { abi::Int(..) | abi::Pointer(_) => RegKind::Integer, - abi::F16 | abi::F32 | abi::F64 | abi::F128 => RegKind::Float, + abi::Float(_) => RegKind::Float, }; Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size })) } diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs index 5d4b3a9d245a4..84f13f8cc5da9 100644 --- a/compiler/rustc_target/src/abi/call/riscv.rs +++ b/compiler/rustc_target/src/abi/call/riscv.rs @@ -65,7 +65,7 @@ where _ => return Err(CannotUseFpConv), } } - abi::F16 | abi::F32 | abi::F64 | abi::F128 => { + abi::Float(_) => { if arg_layout.size.bits() > flen { return Err(CannotUseFpConv); } diff --git a/compiler/rustc_target/src/abi/call/sparc64.rs b/compiler/rustc_target/src/abi/call/sparc64.rs index acdcd5cc0d482..c0952130e0410 100644 --- a/compiler/rustc_target/src/abi/call/sparc64.rs +++ b/compiler/rustc_target/src/abi/call/sparc64.rs @@ -20,7 +20,7 @@ where { let dl = cx.data_layout(); - if !matches!(scalar.primitive(), abi::F32 | abi::F64) { + if !matches!(scalar.primitive(), abi::Float(abi::F32 | abi::F64)) { return data; } @@ -56,7 +56,7 @@ where return data; } - if scalar.primitive() == abi::F32 { + if scalar.primitive() == abi::Float(abi::F32) { data.arg_attribute = ArgAttribute::InReg; data.prefix[data.prefix_index] = Some(Reg::f32()); data.last_offset = offset + Reg::f32().size; @@ -80,14 +80,14 @@ where { data = arg_scalar(cx, scalar1, offset, data); match (scalar1.primitive(), scalar2.primitive()) { - (abi::F32, _) => offset += Reg::f32().size, - (_, abi::F64) => offset += Reg::f64().size, + (abi::Float(abi::F32), _) => offset += Reg::f32().size, + (_, abi::Float(abi::F64)) => offset += Reg::f64().size, (abi::Int(i, _signed), _) => offset += i.size(), (abi::Pointer(_), _) => offset += Reg::i64().size, _ => {} } - if (offset.bytes() % 4) != 0 && matches!(scalar2.primitive(), abi::F32 | abi::F64) { + if (offset.bytes() % 4) != 0 && matches!(scalar2.primitive(), abi::Float(abi::F32 | abi::F64)) { offset += Size::from_bytes(4 - (offset.bytes() % 4)); } data = arg_scalar(cx, scalar2, offset, data); diff --git a/compiler/rustc_target/src/abi/call/x86_64.rs b/compiler/rustc_target/src/abi/call/x86_64.rs index f3208fe5d0351..fcd712489fa40 100644 --- a/compiler/rustc_target/src/abi/call/x86_64.rs +++ b/compiler/rustc_target/src/abi/call/x86_64.rs @@ -51,7 +51,7 @@ where Abi::Scalar(scalar) => match scalar.primitive() { abi::Int(..) | abi::Pointer(_) => Class::Int, - abi::F16 | abi::F32 | abi::F64 | abi::F128 => Class::Sse, + abi::Float(_) => Class::Sse, }, Abi::Vector { .. } => Class::Sse, diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 24e49ff648f2f..666efd9deca28 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -1,4 +1,5 @@ use rustc_data_structures::intern::Interned; +pub use Float::*; pub use Integer::*; pub use Primitive::*; @@ -11,7 +12,8 @@ use rustc_macros::HashStable_Generic; pub mod call; -pub use rustc_abi::*; +// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`. +pub use rustc_abi::{Float, *}; impl ToJson for Endian { fn to_json(&self) -> Json { @@ -207,7 +209,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { C: HasDataLayout, { match self.abi { - Abi::Scalar(scalar) => matches!(scalar.primitive(), F32 | F64), + Abi::Scalar(scalar) => matches!(scalar.primitive(), Float(F32 | F64)), Abi::Aggregate { .. } => { if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 { self.field(cx, 0).is_single_fp_element(cx) diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 84d7930663a30..46c83be9d95f3 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -7,16 +7,17 @@ //! more 'stuff' here in the future. It does not have a dependency on //! LLVM. +// tidy-alphabetical-start +#![allow(internal_features)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] -#![feature(min_exhaustive_patterns)] -#![feature(rustdoc_internals)] #![feature(assert_matches)] #![feature(iter_intersperse)] #![feature(let_chains)] +#![feature(min_exhaustive_patterns)] #![feature(rustc_attrs)] -#![feature(step_trait)] -#![allow(internal_features)] +#![feature(rustdoc_internals)] +// tidy-alphabetical-end use std::path::{Path, PathBuf}; diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index d667bad44e3b7..c5b2065080b20 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -17,14 +17,9 @@ pub enum Arch { Arm64e, Arm64_32, I386, - I386_sim, I686, X86_64, X86_64h, - X86_64_sim, - X86_64_macabi, - Arm64_macabi, - Arm64_sim, } impl Arch { @@ -32,12 +27,12 @@ impl Arch { match self { Armv7k => "armv7k", Armv7s => "armv7s", - Arm64 | Arm64_macabi | Arm64_sim => "arm64", + Arm64 => "arm64", Arm64e => "arm64e", Arm64_32 => "arm64_32", - I386 | I386_sim => "i386", + I386 => "i386", I686 => "i686", - X86_64 | X86_64_sim | X86_64_macabi => "x86_64", + X86_64 => "x86_64", X86_64h => "x86_64h", } } @@ -45,61 +40,70 @@ impl Arch { pub fn target_arch(self) -> Cow<'static, str> { Cow::Borrowed(match self { Armv7k | Armv7s => "arm", - Arm64 | Arm64e | Arm64_32 | Arm64_macabi | Arm64_sim => "aarch64", - I386 | I386_sim | I686 => "x86", - X86_64 | X86_64_sim | X86_64_macabi | X86_64h => "x86_64", + Arm64 | Arm64e | Arm64_32 => "aarch64", + I386 | I686 => "x86", + X86_64 | X86_64h => "x86_64", }) } - fn target_abi(self) -> &'static str { - match self { - Armv7k | Armv7s | Arm64 | Arm64e | Arm64_32 | I386 | I686 | X86_64 | X86_64h => "", - X86_64_macabi | Arm64_macabi => "macabi", - I386_sim | Arm64_sim | X86_64_sim => "sim", - } - } - - fn target_cpu(self) -> &'static str { + fn target_cpu(self, abi: TargetAbi) -> &'static str { match self { Armv7k => "cortex-a8", Armv7s => "swift", // iOS 10 is only supported on iPhone 5 or higher. - Arm64 => "apple-a7", + Arm64 => match abi { + TargetAbi::Normal => "apple-a7", + TargetAbi::Simulator => "apple-a12", + TargetAbi::MacCatalyst => "apple-a12", + }, Arm64e => "apple-a12", Arm64_32 => "apple-s4", // Only macOS 10.12+ is supported, which means // all x86_64/x86 CPUs must be running at least penryn // https://github.com/llvm/llvm-project/blob/01f924d0e37a5deae51df0d77e10a15b63aa0c0f/clang/lib/Driver/ToolChains/Arch/X86.cpp#L79-L82 - I386 | I386_sim | I686 => "penryn", - X86_64 | X86_64_sim => "penryn", - X86_64_macabi => "penryn", + I386 | I686 => "penryn", + X86_64 => "penryn", // Note: `core-avx2` is slightly more advanced than `x86_64h`, see // comments (and disabled features) in `x86_64h_apple_darwin` for // details. It is a higher baseline then `penryn` however. X86_64h => "core-avx2", - Arm64_macabi => "apple-a12", - Arm64_sim => "apple-a12", } } fn stack_probes(self) -> StackProbeType { match self { Armv7k | Armv7s => StackProbeType::None, - Arm64 | Arm64e | Arm64_32 | I386 | I386_sim | I686 | X86_64 | X86_64h | X86_64_sim - | X86_64_macabi | Arm64_macabi | Arm64_sim => StackProbeType::Inline, + Arm64 | Arm64e | Arm64_32 | I386 | I686 | X86_64 | X86_64h => StackProbeType::Inline, } } } -fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs { +#[derive(Copy, Clone, PartialEq)] +pub enum TargetAbi { + Normal, + Simulator, + MacCatalyst, +} + +impl TargetAbi { + fn target_abi(self) -> &'static str { + match self { + Self::Normal => "", + Self::MacCatalyst => "macabi", + Self::Simulator => "sim", + } + } +} + +fn pre_link_args(os: &'static str, arch: Arch, abi: TargetAbi) -> LinkArgs { let platform_name: StaticCow = match abi { - "sim" => format!("{os}-simulator").into(), - "macabi" => "mac-catalyst".into(), - _ => os.into(), + TargetAbi::Normal => os.into(), + TargetAbi::Simulator => format!("{os}-simulator").into(), + TargetAbi::MacCatalyst => "mac-catalyst".into(), }; let min_version: StaticCow = { let (major, minor) = match os { - "ios" => ios_deployment_target(arch, abi), + "ios" => ios_deployment_target(arch, abi.target_abi()), "tvos" => tvos_deployment_target(), "watchos" => watchos_deployment_target(), "visionos" => visionos_deployment_target(), @@ -119,7 +123,7 @@ fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs { LinkerFlavor::Darwin(Cc::No, Lld::No), [platform_name, min_version, sdk_version].into_iter(), ); - if abi != "macabi" { + if abi != TargetAbi::MacCatalyst { add_link_args( &mut args, LinkerFlavor::Darwin(Cc::Yes, Lld::No), @@ -136,13 +140,11 @@ fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs { args } -pub fn opts(os: &'static str, arch: Arch) -> TargetOptions { - let abi = arch.target_abi(); - +pub fn opts(os: &'static str, arch: Arch, abi: TargetAbi) -> TargetOptions { TargetOptions { - abi: abi.into(), + abi: abi.target_abi().into(), os: os.into(), - cpu: arch.target_cpu().into(), + cpu: arch.target_cpu(abi).into(), link_env_remove: link_env_remove(os), vendor: "apple".into(), linker_flavor: LinkerFlavor::Darwin(Cc::Yes, Lld::No), @@ -263,8 +265,7 @@ fn from_set_deployment_target(var_name: &str) -> Option<(u32, u32)> { fn macos_default_deployment_target(arch: Arch) -> (u32, u32) { match arch { - // Note: Arm64_sim is not included since macOS has no simulator. - Arm64 | Arm64e | Arm64_macabi => (11, 0), + Arm64 | Arm64e => (11, 0), _ => (10, 12), } } diff --git a/compiler/rustc_target/src/spec/base/windows_gnu.rs b/compiler/rustc_target/src/spec/base/windows_gnu.rs index 25f02dc145193..1357de2dad126 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnu.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnu.rs @@ -40,6 +40,9 @@ pub fn opts() -> TargetOptions { // // See https://github.com/rust-lang/rust/pull/47483 for some more details. "-lmsvcrt", + // Math functions missing in MSVCRT (they are present in UCRT) require + // this dependency cycle: `libmingwex.a` -> `libmsvcrt.a` -> `libmingwex.a`. + "-lmingwex", "-luser32", "-lkernel32", ]; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index cbb248a0fc21c..8307803676e1c 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -603,19 +603,6 @@ impl LinkSelfContainedDefault { self == LinkSelfContainedDefault::False } - /// Returns whether the target spec explicitly requests self-contained linking, i.e. not via - /// inference. - pub fn is_linker_enabled(self) -> bool { - match self { - LinkSelfContainedDefault::True => true, - LinkSelfContainedDefault::False => false, - LinkSelfContainedDefault::WithComponents(c) => { - c.contains(LinkSelfContainedComponents::LINKER) - } - _ => false, - } - } - /// Returns the key to use when serializing the setting to json: /// - individual components in a `link-self-contained` object value /// - the other variants as a backwards-compatible `crt-objects-fallback` string diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs index eff1617a4bf0b..4e2964174f925 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs @@ -1,9 +1,9 @@ -use crate::spec::base::apple::{macos_llvm_target, opts, Arch}; +use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi}; use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { let arch = Arch::Arm64; - let mut base = opts("macos", arch); + let mut base = opts("macos", arch, TargetAbi::Normal); base.cpu = "apple-m1".into(); base.max_atomic_width = Some(128); @@ -22,7 +22,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: arch.target_arch(), options: TargetOptions { mcount: "\u{1}mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs index e9dddc7fae79a..20655689772d8 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs @@ -1,9 +1,9 @@ -use crate::spec::base::apple::{ios_llvm_target, opts, Arch}; +use crate::spec::base::apple::{ios_llvm_target, opts, Arch, TargetAbi}; use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { let arch = Arch::Arm64; - let mut base = opts("ios", arch); + let mut base = opts("ios", arch, TargetAbi::Normal); base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD; Target { @@ -19,7 +19,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: arch.target_arch(), options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs index 2d89b6083f7ec..4c008f7985e6f 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs @@ -1,9 +1,9 @@ -use crate::spec::base::apple::{mac_catalyst_llvm_target, opts, Arch}; +use crate::spec::base::apple::{mac_catalyst_llvm_target, opts, Arch, TargetAbi}; use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { - let arch = Arch::Arm64_macabi; - let mut base = opts("ios", arch); + let arch = Arch::Arm64; + let mut base = opts("ios", arch, TargetAbi::MacCatalyst); base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD; Target { @@ -15,7 +15,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: arch.target_arch(), options: TargetOptions { features: "+neon,+fp-armv8,+apple-a12".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs index fb4ae02325082..4a63abdf5419f 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs @@ -1,9 +1,9 @@ -use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch}; +use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch, TargetAbi}; use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { - let arch = Arch::Arm64_sim; - let mut base = opts("ios", arch); + let arch = Arch::Arm64; + let mut base = opts("ios", arch, TargetAbi::Simulator); base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD; Target { @@ -19,7 +19,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: arch.target_arch(), options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs index 0deadbdb02810..3310e6c9e8a41 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs @@ -1,4 +1,4 @@ -use crate::spec::base::apple::{opts, tvos_llvm_target, Arch}; +use crate::spec::base::apple::{opts, tvos_llvm_target, Arch, TargetAbi}; use crate::spec::{FramePointer, Target, TargetOptions}; pub fn target() -> Target { @@ -12,13 +12,13 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: arch.target_arch(), options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), frame_pointer: FramePointer::NonLeaf, - ..opts("tvos", arch) + ..opts("tvos", arch, TargetAbi::Normal) }, } } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs index f666c59252429..b901c663afaef 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{opts, tvos_sim_llvm_target, Arch}; +use crate::spec::base::apple::{opts, tvos_sim_llvm_target, Arch, TargetAbi}; use crate::spec::{FramePointer, Target, TargetOptions}; pub fn target() -> Target { - let arch = Arch::Arm64_sim; + let arch = Arch::Arm64; Target { llvm_target: tvos_sim_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { @@ -12,13 +12,13 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: arch.target_arch(), options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), frame_pointer: FramePointer::NonLeaf, - ..opts("tvos", arch) + ..opts("tvos", arch, TargetAbi::Simulator) }, } } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs index 7afe224163bcc..b0798e5e4f580 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs @@ -1,9 +1,9 @@ -use crate::spec::base::apple::{opts, visionos_llvm_target, Arch}; +use crate::spec::base::apple::{opts, visionos_llvm_target, Arch, TargetAbi}; use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { let arch = Arch::Arm64; - let mut base = opts("visionos", arch); + let mut base = opts("visionos", arch, TargetAbi::Normal); base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD; Target { @@ -15,7 +15,7 @@ pub fn target() -> Target { std: Some(false), }, pointer_width: 64, - data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: arch.target_arch(), options: TargetOptions { features: "+neon,+fp-armv8,+apple-a16".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs index 422b2d7b922fc..7b2d2b6a8e442 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs @@ -1,9 +1,9 @@ -use crate::spec::base::apple::{opts, visionos_sim_llvm_target, Arch}; +use crate::spec::base::apple::{opts, visionos_sim_llvm_target, Arch, TargetAbi}; use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { - let arch = Arch::Arm64_sim; - let mut base = opts("visionos", arch); + let arch = Arch::Arm64; + let mut base = opts("visionos", arch, TargetAbi::Simulator); base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD; Target { @@ -15,7 +15,7 @@ pub fn target() -> Target { std: Some(false), }, pointer_width: 64, - data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: arch.target_arch(), options: TargetOptions { features: "+neon,+fp-armv8,+apple-a16".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs index 5001444e1fae6..a00a97a133f60 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{opts, Arch}; +use crate::spec::base::apple::{opts, Arch, TargetAbi}; use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { - let base = opts("watchos", Arch::Arm64); + let base = opts("watchos", Arch::Arm64, TargetAbi::Normal); Target { llvm_target: "aarch64-apple-watchos".into(), metadata: crate::spec::TargetMetadata { @@ -12,7 +12,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { features: "+v8a,+neon,+fp-armv8,+apple-a7".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs index 5728f55baba0f..e2f80b7b7a888 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{opts, watchos_sim_llvm_target, Arch}; +use crate::spec::base::apple::{opts, watchos_sim_llvm_target, Arch, TargetAbi}; use crate::spec::{FramePointer, Target, TargetOptions}; pub fn target() -> Target { - let arch = Arch::Arm64_sim; + let arch = Arch::Arm64; Target { // Clang automatically chooses a more specific target based on // WATCHOS_DEPLOYMENT_TARGET. @@ -16,13 +16,13 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: arch.target_arch(), options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".into(), max_atomic_width: Some(128), frame_pointer: FramePointer::NonLeaf, - ..opts("watchos", arch) + ..opts("watchos", arch, TargetAbi::Simulator) }, } } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs index 716c9b15c5921..88115b81fa5b9 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { features: "+v8a,+outline-atomics".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs index f3b6c4c618023..b89c2841dae75 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_linux_gnu_ilp32.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 32, - data_layout: "E-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "E-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { abi: "ilp32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs index 54108cc1fe005..d9164f8b052ec 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_netbsd.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { mcount: "__mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs b/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs index aa8c4cd0d0857..168f6ad1ac2b7 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_kmc_solid_asp3.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { linker: Some("aarch64-kmc-elf-gcc".into()), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs index bb9bab4569bb4..e9fa482bff103 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_linux_android.rs @@ -13,7 +13,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { max_atomic_width: Some(128), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs b/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs index 15743b9e5085e..7e7e202b11218 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs @@ -15,7 +15,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { features: "+v8a".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs index aed7f94bab7b3..2cc417ea83092 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_gnullvm.rs @@ -15,7 +15,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs index f253b014c31d3..a5e7dda5fb8ad 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_pc_windows_msvc.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs index 9fec76b891cbf..81c9d5927fa22 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_freebsd.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { features: "+v8a".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs index 21789e436cac7..d740f0b7c97ab 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { features: "+v8a".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs index 9ffea48cba715..a466fa055164a 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_hermit.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { }, pointer_width: 64, arch: "aarch64".into(), - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), options: TargetOptions { features: "+v8a,+strict-align,+neon,+fp-armv8".into(), max_atomic_width: Some(128), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs index 90130880ace71..6f253c2a22393 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_illumos.rs @@ -18,7 +18,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs index 703a3206af21f..0c4bac0e1295e 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { features: "+v8a,+outline-atomics".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs index 81c6a18366915..e202ce2f57f62 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_gnu_ilp32.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 32, - data_layout: "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-p:32:32-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { abi: "ilp32".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs index 77689e26380d5..4a82423bb636a 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_musl.rs @@ -21,7 +21,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { mcount: "\u{1}_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs index b6b25598bec55..3d357bcf3f233 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_linux_ohos.rs @@ -15,7 +15,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { features: "+reserve-x18".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs index de88b3fe795d6..ac26aa8227162 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_netbsd.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { features: "+v8a".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs index e5a428aade210..21706aa0b5d85 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none.rs @@ -38,7 +38,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: opts, } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs index c75b0d468e8dd..4f04a7816ce84 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_none_softfloat.rs @@ -32,7 +32,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: opts, } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs index f2f1b477ff86a..8e448a2fa9a7a 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_nto_qnx710.rs @@ -19,7 +19,7 @@ pub fn target() -> Target { // i128:128 = 128-bit-integer, minimum_alignment=128, preferred_alignment=128 // n32:64 = 32 and 64 are native integer widths; Elements of this set are considered to support most general arithmetic operations efficiently. // S128 = 128 bits are the natural alignment of the stack in bits. - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { features: "+v8a".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs index f0d79d3c4b738..b51cddafb1aa8 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_openbsd.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { features: "+v8a".into(), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs index b7e9d8cb9fc52..544709cffe673 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_redox.rs @@ -15,7 +15,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs index cb48b7417b0c4..285c5e79cf052 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_teeos.rs @@ -15,7 +15,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs index e8d8770546c7d..de4a56ae03da3 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_uefi.rs @@ -19,7 +19,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs index 7a89237d0fff7..50064e673b3d3 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_uwp_windows_msvc.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs index ab23ff6ad9b6b..026b30e9eb789 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_wrs_vxworks.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { features: "+v8a".into(), 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 f842a834c05bf..3ca8c9969c2d5 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,9 +1,9 @@ -use crate::spec::base::apple::{opts, watchos_llvm_target, Arch}; +use crate::spec::base::apple::{opts, watchos_llvm_target, Arch, TargetAbi}; use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { let arch = Arch::Arm64_32; - let base = opts("watchos", arch); + let base = opts("watchos", arch, TargetAbi::Normal); Target { llvm_target: watchos_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { @@ -13,7 +13,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 32, - data_layout: "e-m:o-p:32:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:o-p:32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { features: "+v8a,+neon,+fp-armv8,+apple-a7".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs index 11c56cf411c37..90be518638e93 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs @@ -1,9 +1,9 @@ -use crate::spec::base::apple::{macos_llvm_target, opts, Arch}; +use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi}; use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { let arch = Arch::Arm64e; - let mut base = opts("macos", arch); + let mut base = opts("macos", arch, TargetAbi::Normal); base.cpu = "apple-m1".into(); base.max_atomic_width = Some(128); @@ -22,7 +22,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: arch.target_arch(), options: TargetOptions { mcount: "\u{1}mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs index fd8f0ddcb4ddd..56470d29eae00 100644 --- a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs @@ -1,9 +1,9 @@ -use crate::spec::base::apple::{ios_llvm_target, opts, Arch}; +use crate::spec::base::apple::{ios_llvm_target, opts, Arch, TargetAbi}; use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { let arch = Arch::Arm64e; - let mut base = opts("ios", arch); + let mut base = opts("ios", arch, TargetAbi::Normal); base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD; Target { @@ -19,7 +19,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:o-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: arch.target_arch(), options: TargetOptions { features: "+neon,+fp-armv8,+apple-a12,+v8.3a,+pauth".into(), diff --git a/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs index bfd3364acacca..aedfb88102462 100644 --- a/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/targets/arm64ec_pc_windows_msvc.rs @@ -19,7 +19,7 @@ pub fn target() -> Target { std: None, }, pointer_width: 64, - data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".into(), + data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "arm64ec".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs index 42ad9e0a35e6a..5c675c22ef511 100644 --- a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs @@ -1,4 +1,4 @@ -use crate::spec::base::apple::{opts, Arch}; +use crate::spec::base::apple::{opts, Arch, TargetAbi}; use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { @@ -19,7 +19,7 @@ pub fn target() -> Target { max_atomic_width: Some(64), dynamic_linking: false, position_independent_executables: true, - ..opts("watchos", arch) + ..opts("watchos", arch, TargetAbi::Normal) }, } } diff --git a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs index 40e5fc3f20dab..4dd475e3a82da 100644 --- a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs @@ -1,4 +1,4 @@ -use crate::spec::base::apple::{ios_llvm_target, opts, Arch}; +use crate::spec::base::apple::{ios_llvm_target, opts, Arch, TargetAbi}; use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { @@ -17,7 +17,7 @@ pub fn target() -> Target { options: TargetOptions { features: "+v7,+vfp4,+neon".into(), max_atomic_width: Some(64), - ..opts("ios", arch) + ..opts("ios", arch, TargetAbi::Normal) }, } } diff --git a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs index afa92ba99c61f..c03a0974bc1cb 100644 --- a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs @@ -1,10 +1,11 @@ -use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch}; +use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch, TargetAbi}; use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { + let arch = Arch::I386; // i386-apple-ios is a simulator target, even though it isn't declared // that way in the target name like the other ones... - let arch = Arch::I386_sim; + let abi = TargetAbi::Simulator; Target { // Clang automatically chooses a more specific target based on // IPHONEOS_DEPLOYMENT_TARGET. @@ -22,6 +23,6 @@ pub fn target() -> Target { i128:128-f64:32:64-f80:128-n8:16:32-S128" .into(), arch: arch.target_arch(), - options: TargetOptions { max_atomic_width: Some(64), ..opts("ios", arch) }, + options: TargetOptions { max_atomic_width: Some(64), ..opts("ios", arch, abi) }, } } diff --git a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs index 34a447a97efb8..aea6a1ac4ecea 100644 --- a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs @@ -1,10 +1,10 @@ -use crate::spec::base::apple::{macos_llvm_target, opts, Arch}; +use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi}; use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target, TargetOptions}; pub fn target() -> Target { // ld64 only understands i386 and not i686 let arch = Arch::I386; - let mut base = opts("macos", arch); + let mut base = opts("macos", arch, TargetAbi::Normal); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m32"]); base.frame_pointer = FramePointer::Always; diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs index 5ff3f07daae84..1259969ac3655 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs @@ -18,7 +18,7 @@ use crate::spec::crt_objects; use crate::spec::LinkSelfContainedDefault; -use crate::spec::{base, Target}; +use crate::spec::{base, RelocModel, Target}; pub fn target() -> Target { let mut options = base::wasm::options(); @@ -54,8 +54,13 @@ pub fn target() -> Target { // signatures. options.entry_name = "__main_void".into(); + // Default to PIC unlike base wasm. This makes precompiled objects such as + // the standard library more suitable to be used with shared libaries a la + // emscripten's dynamic linking convention. + options.relocation_model = RelocModel::Pic; + Target { - llvm_target: "wasm32-unknown-unknown".into(), + llvm_target: "wasm32-wasip2".into(), metadata: crate::spec::TargetMetadata { description: None, tier: None, diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs index 1716c590aa503..21acd750df2dc 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs @@ -1,10 +1,10 @@ -use crate::spec::base::apple::{macos_llvm_target, opts, Arch}; +use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi}; use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet}; use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { let arch = Arch::X86_64; - let mut base = opts("macos", arch); + let mut base = opts("macos", arch, TargetAbi::Normal); base.max_atomic_width = Some(128); // penryn+ supports cmpxchg16b base.frame_pointer = FramePointer::Always; base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]); diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs index fa22c2907d271..ec61b7967646e 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs @@ -1,11 +1,11 @@ -use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch}; +use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch, TargetAbi}; use crate::spec::{SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { + let arch = Arch::X86_64; // x86_64-apple-ios is a simulator target, even though it isn't declared // that way in the target name like the other ones... - let arch = Arch::X86_64_sim; - let mut base = opts("ios", arch); + let mut base = opts("ios", arch, TargetAbi::Simulator); base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD; Target { diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs index 9b479de81652c..bd967ee972b32 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs @@ -1,9 +1,9 @@ -use crate::spec::base::apple::{mac_catalyst_llvm_target, opts, Arch}; +use crate::spec::base::apple::{mac_catalyst_llvm_target, opts, Arch, TargetAbi}; use crate::spec::{SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { - let arch = Arch::X86_64_macabi; - let mut base = opts("ios", arch); + let arch = Arch::X86_64; + let mut base = opts("ios", arch, TargetAbi::MacCatalyst); base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD; Target { diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs index f62d31c51662b..55b2e1afcd392 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs @@ -1,10 +1,11 @@ -use crate::spec::base::apple::{opts, tvos_sim_llvm_target, Arch}; +use crate::spec::base::apple::{opts, tvos_sim_llvm_target, Arch, TargetAbi}; use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { + let arch = Arch::X86_64; // x86_64-apple-tvos is a simulator target, even though it isn't declared // that way in the target name like the other ones... - let arch = Arch::X86_64_sim; + let abi = TargetAbi::Simulator; Target { llvm_target: tvos_sim_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { @@ -17,6 +18,6 @@ pub fn target() -> Target { data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: arch.target_arch(), - options: TargetOptions { max_atomic_width: Some(128), ..opts("tvos", arch) }, + options: TargetOptions { max_atomic_width: Some(128), ..opts("tvos", arch, abi) }, } } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs index 371aab8b50805..a783eff15b261 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs @@ -1,8 +1,8 @@ -use crate::spec::base::apple::{opts, watchos_sim_llvm_target, Arch}; +use crate::spec::base::apple::{opts, watchos_sim_llvm_target, Arch, TargetAbi}; use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { - let arch = Arch::X86_64_sim; + let arch = Arch::X86_64; Target { llvm_target: watchos_sim_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { @@ -15,6 +15,9 @@ pub fn target() -> Target { data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: arch.target_arch(), - options: TargetOptions { max_atomic_width: Some(128), ..opts("watchos", arch) }, + options: TargetOptions { + max_atomic_width: Some(128), + ..opts("watchos", arch, TargetAbi::Simulator) + }, } } diff --git a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs index b17e21e5d1206..fe6cbca32c748 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs @@ -1,10 +1,10 @@ -use crate::spec::base::apple::{macos_llvm_target, opts, Arch}; +use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi}; use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet}; use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { let arch = Arch::X86_64h; - let mut base = opts("macos", arch); + let mut base = opts("macos", arch, TargetAbi::Normal); base.max_atomic_width = Some(128); base.frame_pointer = FramePointer::Always; base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]); diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 7228a9ba01672..b442446f79bab 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -4,7 +4,7 @@ use rustc_errors::{ SubdiagMessageOp, Subdiagnostic, }; use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_middle::ty::{self, ClosureKind, PolyTraitRef, Ty}; +use rustc_middle::ty::{self, print::PrintTraitRefExt as _, ClosureKind, PolyTraitRef, Ty}; use rustc_span::{Span, Symbol}; #[derive(Diagnostic)] diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index f2c441dcbeda6..e079809aecc99 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -20,7 +20,7 @@ use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; use rustc_middle::ty; impl<'tcx> EvalCtxt<'_, 'tcx> { - #[instrument(level = "debug", skip(self), ret)] + #[instrument(level = "trace", skip(self), ret)] pub(super) fn compute_alias_relate_goal( &mut self, goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>, @@ -50,7 +50,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.try_evaluate_added_goals()?; let lhs = self.resolve_vars_if_possible(lhs); let rhs = self.resolve_vars_if_possible(rhs); - debug!(?lhs, ?rhs); + trace!(?lhs, ?rhs); let variance = match direction { ty::AliasRelationDirection::Equate => ty::Variance::Invariant, diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index f2ca42a0be91e..938bd80b9eb0a 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -331,7 +331,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { .enter(|this| this.evaluate_added_goals_and_make_canonical_response(certainty)) } - #[instrument(level = "debug", skip_all)] + #[instrument(level = "trace", skip_all)] fn assemble_non_blanket_impl_candidates>( &mut self, goal: Goal<'tcx, G>, @@ -447,7 +447,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - #[instrument(level = "debug", skip_all)] + #[instrument(level = "trace", skip_all)] fn assemble_blanket_impl_candidates>( &mut self, goal: Goal<'tcx, G>, @@ -470,7 +470,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - #[instrument(level = "debug", skip_all)] + #[instrument(level = "trace", skip_all)] fn assemble_builtin_impl_candidates>( &mut self, goal: Goal<'tcx, G>, @@ -544,7 +544,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - #[instrument(level = "debug", skip_all)] + #[instrument(level = "trace", skip_all)] fn assemble_param_env_candidates>( &mut self, goal: Goal<'tcx, G>, @@ -561,7 +561,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - #[instrument(level = "debug", skip_all)] + #[instrument(level = "trace", skip_all)] fn assemble_alias_bound_candidates>( &mut self, goal: Goal<'tcx, G>, @@ -665,7 +665,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - #[instrument(level = "debug", skip_all)] + #[instrument(level = "trace", skip_all)] fn assemble_object_bound_candidates>( &mut self, goal: Goal<'tcx, G>, @@ -756,7 +756,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// /// To do so we add an ambiguous candidate in case such an unknown impl could /// apply to the current goal. - #[instrument(level = "debug", skip_all)] + #[instrument(level = "trace", skip_all)] fn assemble_coherence_unknowable_candidates>( &mut self, goal: Goal<'tcx, G>, 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 a8b1a182d3c23..eeaef028cdb4d 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -17,7 +17,7 @@ use crate::solve::EvalCtxt; // // For types with an "existential" binder, i.e. coroutine witnesses, we also // instantiate the binder with placeholders eagerly. -#[instrument(level = "debug", skip(ecx), ret)] +#[instrument(level = "trace", skip(ecx), ret)] pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ecx: &EvalCtxt<'_, 'tcx>, ty: Ty<'tcx>, @@ -96,7 +96,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( } } -#[instrument(level = "debug", skip(ecx), ret)] +#[instrument(level = "trace", skip(ecx), ret)] pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( ecx: &EvalCtxt<'_, 'tcx>, ty: Ty<'tcx>, @@ -160,7 +160,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( } } -#[instrument(level = "debug", skip(ecx), ret)] +#[instrument(level = "trace", skip(ecx), ret)] pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ecx: &EvalCtxt<'_, 'tcx>, ty: Ty<'tcx>, 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 d6bf2b596ef1e..d5176dc321c08 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -19,12 +19,10 @@ use rustc_infer::infer::canonical::query_response::make_query_region_constraints use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; use rustc_infer::infer::resolve::EagerResolver; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::RegionVariableOrigin; use rustc_infer::infer::{InferCtxt, InferOk}; use rustc_infer::traits::solve::NestedNormalizationGoals; use rustc_middle::infer::canonical::Canonical; -use rustc_middle::infer::unify_key::ConstVariableOrigin; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{ ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput, @@ -85,7 +83,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// the values inferred while solving the instantiated goal. /// - `external_constraints`: additional constraints which aren't expressible /// using simple unification of inference variables. - #[instrument(level = "debug", skip(self), ret)] + #[instrument(level = "trace", skip(self), ret)] pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response( &mut self, certainty: Certainty, @@ -168,7 +166,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// external constraints do not need to record that opaque, since if it is /// further constrained by inference, that will be passed back in the var /// values. - #[instrument(level = "debug", skip(self), ret)] + #[instrument(level = "trace", skip(self), ret)] fn compute_external_query_constraints( &self, normalization_nested_goals: NestedNormalizationGoals<'tcx>, @@ -176,7 +174,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { // We only check for leaks from universes which were entered inside // of the query. self.infcx.leak_check(self.max_input_universe, None).map_err(|e| { - debug!(?e, "failed the leak check"); + trace!(?e, "failed the leak check"); NoSolution })?; @@ -236,7 +234,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { normalization_nested_goals, } = external_constraints.deref(); self.register_region_constraints(region_constraints); - self.register_new_opaque_types(param_env, opaque_types); + self.register_new_opaque_types(opaque_types); (normalization_nested_goals.clone(), certainty) } @@ -336,7 +334,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// whether an alias is rigid by using the trait solver. When instantiating a response /// from the solver we assume that the solver correctly handled aliases and therefore /// always relate them structurally here. - #[instrument(level = "debug", skip(infcx))] + #[instrument(level = "trace", skip(infcx))] fn unify_query_var_values( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -368,13 +366,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { assert!(region_constraints.member_constraints.is_empty()); } - fn register_new_opaque_types( - &mut self, - param_env: ty::ParamEnv<'tcx>, - opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)], - ) { + fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)]) { for &(key, ty) in opaque_types { - self.insert_hidden_type(key, param_env, ty).unwrap(); + let hidden_ty = ty::OpaqueHiddenType { ty, span: DUMMY_SP }; + self.infcx.inject_new_hidden_type_unchecked(key, hidden_ty); } } } @@ -412,6 +407,7 @@ pub(in crate::solve) fn make_canonical_state<'tcx, T: TypeFoldable> /// This currently assumes that unifying the var values trivially succeeds. /// Adding any inference constraints which weren't present when originally /// computing the canonical query can result in bugs. +#[instrument(level = "trace", skip(infcx, span, param_env))] pub(in crate::solve) fn instantiate_canonical_state<'tcx, T: TypeFoldable>>( infcx: &InferCtxt<'tcx>, span: Span, @@ -427,12 +423,8 @@ pub(in crate::solve) fn instantiate_canonical_state<'tcx, T: TypeFoldable { infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)).into() } - ty::GenericArgKind::Type(_) => { - infcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span }).into() - } - ty::GenericArgKind::Const(ct) => infcx - .next_const_var(ct.ty(), ConstVariableOrigin { param_def_id: None, span }) - .into(), + ty::GenericArgKind::Type(_) => infcx.next_ty_var(span).into(), + ty::GenericArgKind::Const(ct) => infcx.next_const_var(ct.ty(), span).into(), }; orig_values.push(unconstrained); 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 773babde0d7b3..8614c17cabf1d 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -2,7 +2,6 @@ use rustc_data_structures::stack::ensure_sufficient_stack; 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; use rustc_infer::infer::{ BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt, }; @@ -11,7 +10,6 @@ use rustc_infer::traits::solve::{MaybeCause, NestedNormalizationGoals}; use rustc_infer::traits::ObligationCause; use rustc_macros::{extension, HashStable}; use rustc_middle::infer::canonical::CanonicalVarInfos; -use rustc_middle::infer::unify_key::ConstVariableOrigin; use rustc_middle::traits::solve::inspect; use rustc_middle::traits::solve::{ CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaques, PredefinedOpaquesData, @@ -248,8 +246,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { }; for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { - ecx.insert_hidden_type(key, input.goal.param_env, ty) - .expect("failed to prepopulate opaque types"); + let hidden_ty = ty::OpaqueHiddenType { ty, span: DUMMY_SP }; + ecx.infcx.inject_new_hidden_type_unchecked(key, hidden_ty); } if !ecx.nested_goals.is_empty() { @@ -460,7 +458,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } } - #[instrument(level = "debug", skip(self))] + #[instrument(level = "trace", skip(self))] pub(super) fn add_normalizes_to_goal(&mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) { self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal); self.nested_goals.normalizes_to_goals.push(goal); @@ -474,7 +472,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { // Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning // the certainty of all the goals. - #[instrument(level = "debug", skip(self))] + #[instrument(level = "trace", skip(self))] pub(super) fn try_evaluate_added_goals(&mut self) -> Result { self.inspect.start_evaluate_added_goals(); let mut response = Ok(Certainty::overflow(false)); @@ -528,7 +526,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { unconstrained_goal, )?; // Add the nested goals from normalization to our own nested goals. - debug!(?nested_goals); + trace!(?nested_goals); goals.goals.extend(nested_goals); // Finally, equate the goal's RHS with the unconstrained var. @@ -587,6 +585,11 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { Ok(unchanged_certainty) } + + /// Record impl args in the proof tree for later access by `InspectCandidate`. + pub(crate) fn record_impl_args(&mut self, impl_args: ty::GenericArgsRef<'tcx>) { + self.inspect.record_impl_args(self.infcx, self.max_input_universe, impl_args) + } } impl<'tcx> EvalCtxt<'_, 'tcx> { @@ -595,15 +598,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } pub(super) fn next_ty_infer(&mut self) -> Ty<'tcx> { - let ty = self.infcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span: DUMMY_SP }); + let ty = self.infcx.next_ty_var(DUMMY_SP); self.inspect.add_var_value(ty); ty } pub(super) fn next_const_infer(&mut self, ty: Ty<'tcx>) -> ty::Const<'tcx> { - let ct = self - .infcx - .next_const_var(ty, ConstVariableOrigin { param_def_id: None, span: DUMMY_SP }); + let ct = self.infcx.next_const_var(ty, DUMMY_SP); self.inspect.add_var_value(ct); ct } @@ -621,7 +622,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// /// This is the case if the `term` does not occur in any other part of the predicate /// and is able to name all other placeholder and inference variables. - #[instrument(level = "debug", skip(self), ret)] + #[instrument(level = "trace", skip(self), ret)] pub(super) fn term_is_fully_unconstrained( &self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, @@ -717,7 +718,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { && goal.param_env.visit_with(&mut visitor).is_continue() } - #[instrument(level = "debug", skip(self, param_env), ret)] + #[instrument(level = "trace", skip(self, param_env), ret)] pub(super) fn eq>( &mut self, param_env: ty::ParamEnv<'tcx>, @@ -732,7 +733,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into())); }) .map_err(|e| { - debug!(?e, "failed to equate"); + trace!(?e, "failed to equate"); NoSolution }) } @@ -742,7 +743,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// Normally we emit a nested `AliasRelate` when equating an inference /// variable and an alias. This causes us to instead constrain the inference /// variable to the alias without emitting a nested alias relate goals. - #[instrument(level = "debug", skip(self, param_env), ret)] + #[instrument(level = "trace", skip(self, param_env), ret)] pub(super) fn relate_rigid_alias_non_alias( &mut self, param_env: ty::ParamEnv<'tcx>, @@ -780,7 +781,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// This sohuld only be used when we're either instantiating a previously /// unconstrained "return value" or when we're sure that all aliases in /// the types are rigid. - #[instrument(level = "debug", skip(self, param_env), ret)] + #[instrument(level = "trace", skip(self, param_env), ret)] pub(super) fn eq_structurally_relating_aliases>( &mut self, param_env: ty::ParamEnv<'tcx>, @@ -797,7 +798,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { Ok(()) } - #[instrument(level = "debug", skip(self, param_env), ret)] + #[instrument(level = "trace", skip(self, param_env), ret)] pub(super) fn sub>( &mut self, param_env: ty::ParamEnv<'tcx>, @@ -812,12 +813,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into())); }) .map_err(|e| { - debug!(?e, "failed to subtype"); + trace!(?e, "failed to subtype"); NoSolution }) } - #[instrument(level = "debug", skip(self, param_env), ret)] + #[instrument(level = "trace", skip(self, param_env), ret)] pub(super) fn relate>( &mut self, param_env: ty::ParamEnv<'tcx>, @@ -833,7 +834,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into())); }) .map_err(|e| { - debug!(?e, "failed to relate"); + trace!(?e, "failed to relate"); NoSolution }) } @@ -858,7 +859,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { obligations.into_iter().map(|o| o.into()).collect() }) .map_err(|e| { - debug!(?e, "failed to equate"); + trace!(?e, "failed to equate"); NoSolution }) } @@ -1047,12 +1048,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ty: Ty<'tcx>, ) -> Option> { use rustc_middle::mir::interpret::ErrorHandled; - match self.infcx.try_const_eval_resolve(param_env, unevaluated, ty, DUMMY_SP) { - Ok(ct) => Some(ct), + match self.infcx.const_eval_resolve(param_env, unevaluated, DUMMY_SP) { + Ok(Some(val)) => Some(ty::Const::new_value(self.tcx(), val, ty)), + Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None, Err(ErrorHandled::Reported(e, _)) => { Some(ty::Const::new_error(self.tcx(), e.into(), ty)) } - Err(ErrorHandled::TooGeneric(_)) => None, } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs index ee23f49939b7c..47109c8ad5d2f 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs @@ -58,6 +58,7 @@ impl<'tcx, F> TraitProbeCtxt<'_, '_, 'tcx, F> where F: FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>, { + #[instrument(level = "debug", skip_all, fields(source = ?self.source))] pub(in crate::solve) fn enter( self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs index 16fe045b82de7..7efc951135b79 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs @@ -1,12 +1,11 @@ use std::ops::ControlFlow; -use rustc_hir::def_id::DefId; -use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; +use rustc_infer::infer::InferCtxt; use rustc_infer::traits::solve::inspect::ProbeKind; use rustc_infer::traits::solve::{CandidateSource, Certainty, Goal}; use rustc_infer::traits::{ BuiltinImplSource, ImplSource, ImplSourceUserDefinedData, Obligation, ObligationCause, - PolyTraitObligation, PredicateObligation, Selection, SelectionError, SelectionResult, + PolyTraitObligation, Selection, SelectionError, SelectionResult, }; use rustc_macros::extension; use rustc_span::Span; @@ -58,6 +57,12 @@ impl<'tcx> inspect::ProofTreeVisitor<'tcx> for Select { ))); } + // Don't winnow until `Certainty::Yes` -- we don't need to winnow until + // codegen, and only on the good path. + if matches!(goal.result().unwrap(), Certainty::Maybe(..)) { + return ControlFlow::Break(Ok(None)); + } + // We need to winnow. See comments on `candidate_should_be_dropped_in_favor_of`. let mut i = 0; while i < candidates.len() { @@ -86,7 +91,7 @@ fn candidate_should_be_dropped_in_favor_of<'tcx>( other: &inspect::InspectCandidate<'_, 'tcx>, ) -> bool { // Don't winnow until `Certainty::Yes` -- we don't need to winnow until - // codegen, technically. + // codegen, and only on the good path. if matches!(other.result().unwrap(), Certainty::Maybe(..)) { return false; } @@ -105,12 +110,14 @@ fn candidate_should_be_dropped_in_favor_of<'tcx>( bug!("should not have assembled a CoherenceUnknowable candidate") } + // In the old trait solver, we arbitrarily choose lower vtable candidates + // over higher ones. + ( + CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base: a }), + CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base: b }), + ) => a >= b, // Prefer dyn candidates over non-dyn candidates. This is necessary to // handle the unsoundness between `impl Any for T` and `dyn Any: Any`. - ( - CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }), - CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }), - ) => false, ( CandidateSource::Impl(_) | CandidateSource::ParamEnv(_) | CandidateSource::AliasBound, CandidateSource::BuiltinImpl(BuiltinImplSource::Object { .. }), @@ -133,32 +140,32 @@ fn to_selection<'tcx>( return None; } - let make_nested = || { - cand.instantiate_nested_goals(span) - .into_iter() - .map(|nested| { - Obligation::new( - nested.infcx().tcx, - ObligationCause::dummy_with_span(span), - nested.goal().param_env, - nested.goal().predicate, - ) - }) - .collect() - }; + let (nested, impl_args) = cand.instantiate_nested_goals_and_opt_impl_args(span); + let nested = nested + .into_iter() + .map(|nested| { + Obligation::new( + nested.infcx().tcx, + ObligationCause::dummy_with_span(span), + nested.goal().param_env, + nested.goal().predicate, + ) + }) + .collect(); Some(match cand.kind() { ProbeKind::TraitCandidate { source, result: _ } => match source { CandidateSource::Impl(impl_def_id) => { // FIXME: Remove this in favor of storing this in the tree // For impl candidates, we do the rematch manually to compute the args. - ImplSource::UserDefined(rematch_impl(cand.goal(), impl_def_id, span)) - } - CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, make_nested()), - CandidateSource::ParamEnv(_) => ImplSource::Param(make_nested()), - CandidateSource::AliasBound => { - ImplSource::Builtin(BuiltinImplSource::Misc, make_nested()) + ImplSource::UserDefined(ImplSourceUserDefinedData { + impl_def_id, + args: impl_args.expect("expected recorded impl args for impl candidate"), + nested, + }) } + CandidateSource::BuiltinImpl(builtin) => ImplSource::Builtin(builtin, nested), + CandidateSource::ParamEnv(_) | CandidateSource::AliasBound => ImplSource::Param(nested), CandidateSource::CoherenceUnknowable => { span_bug!(span, "didn't expect to select an unknowable candidate") } @@ -173,40 +180,3 @@ fn to_selection<'tcx>( } }) } - -fn rematch_impl<'tcx>( - goal: &inspect::InspectGoal<'_, 'tcx>, - impl_def_id: DefId, - span: Span, -) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { - let infcx = goal.infcx(); - let goal_trait_ref = infcx - .enter_forall_and_leak_universe(goal.goal().predicate.to_opt_poly_trait_pred().unwrap()) - .trait_ref; - - let args = infcx.fresh_args_for_item(span, impl_def_id); - let impl_trait_ref = - infcx.tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(infcx.tcx, args); - - let InferOk { value: (), obligations: mut nested } = infcx - .at(&ObligationCause::dummy_with_span(span), goal.goal().param_env) - .eq(DefineOpaqueTypes::Yes, goal_trait_ref, impl_trait_ref) - .expect("rematching impl failed"); - - // FIXME(-Znext-solver=coinductive): We need to add supertraits here eventually. - - nested.extend( - infcx.tcx.predicates_of(impl_def_id).instantiate(infcx.tcx, args).into_iter().map( - |(clause, _)| { - Obligation::new( - infcx.tcx, - ObligationCause::dummy_with_span(span), - goal.goal().param_env, - clause, - ) - }, - ), - ); - - ImplSourceUserDefinedData { impl_def_id, nested, args } -} diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index fd4b5805f027d..586d2095d9c0e 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -7,14 +7,14 @@ use rustc_infer::traits::solve::inspect::ProbeKind; use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause}; use rustc_infer::traits::{ self, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation, - ObligationCause, PredicateObligation, SelectionError, TraitEngine, + ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError, TraitEngine, }; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::sym; use super::eval_ctxt::GenerateProofTree; -use super::inspect::{ProofTreeInferCtxtExt, ProofTreeVisitor}; +use super::inspect::{InspectCandidate, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor}; use super::{Certainty, InferCtxtEvalExt}; /// A trait engine using the new trait solver. @@ -119,7 +119,7 @@ impl<'tcx> FulfillmentCtxt<'tcx> { } impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { - #[instrument(level = "debug", skip(self, infcx))] + #[instrument(level = "trace", skip(self, infcx))] fn register_predicate_obligation( &mut self, infcx: &InferCtxt<'tcx>, @@ -203,39 +203,35 @@ fn fulfillment_error_for_no_solution<'tcx>( let code = match obligation.predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => { - FulfillmentErrorCode::ProjectionError( + FulfillmentErrorCode::Project( // FIXME: This could be a `Sorts` if the term is a type MismatchedProjectionTypes { err: TypeError::Mismatch }, ) } ty::PredicateKind::NormalizesTo(..) => { - FulfillmentErrorCode::ProjectionError(MismatchedProjectionTypes { - err: TypeError::Mismatch, - }) + FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch }) } ty::PredicateKind::AliasRelate(_, _, _) => { - FulfillmentErrorCode::ProjectionError(MismatchedProjectionTypes { - err: TypeError::Mismatch, - }) + FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch }) } ty::PredicateKind::Subtype(pred) => { let (a, b) = infcx.enter_forall_and_leak_universe( obligation.predicate.kind().rebind((pred.a, pred.b)), ); let expected_found = ExpectedFound::new(true, a, b); - FulfillmentErrorCode::SubtypeError(expected_found, TypeError::Sorts(expected_found)) + FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found)) } ty::PredicateKind::Coerce(pred) => { let (a, b) = infcx.enter_forall_and_leak_universe( obligation.predicate.kind().rebind((pred.a, pred.b)), ); let expected_found = ExpectedFound::new(false, a, b); - FulfillmentErrorCode::SubtypeError(expected_found, TypeError::Sorts(expected_found)) + FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found)) } ty::PredicateKind::Clause(_) | ty::PredicateKind::ObjectSafe(_) | ty::PredicateKind::Ambiguous => { - FulfillmentErrorCode::SelectionError(SelectionError::Unimplemented) + FulfillmentErrorCode::Select(SelectionError::Unimplemented) } ty::PredicateKind::ConstEquate(..) => { bug!("unexpected goal: {obligation:?}") @@ -304,6 +300,46 @@ impl<'tcx> BestObligation<'tcx> { self.obligation = old_obligation; res } + + /// Filter out the candidates that aren't either error or ambiguous (depending + /// on what we are looking for), and also throw out candidates that have no + /// failing WC (or higher-ranked obligations, for which there should only be + /// one candidate anyways -- but I digress). This most likely means that the + /// goal just didn't unify at all, e.g. a param candidate with an alias in it. + fn non_trivial_candidates<'a>( + &self, + goal: &'a InspectGoal<'a, 'tcx>, + ) -> Vec> { + let mut candidates = goal + .candidates() + .into_iter() + .filter(|candidate| match self.consider_ambiguities { + true => matches!(candidate.result(), Ok(Certainty::Maybe(_))), + false => matches!(candidate.result(), Err(_)), + }) + .collect::>(); + + // If we have >1 candidate, one may still be due to "boring" reasons, like + // an alias-relate that failed to hold when deeply evaluated. We really + // don't care about reasons like this. + if candidates.len() > 1 { + candidates.retain(|candidate| { + goal.infcx().probe(|_| { + candidate.instantiate_nested_goals(self.span()).iter().any(|nested_goal| { + matches!( + nested_goal.source(), + GoalSource::ImplWhereBound | GoalSource::InstantiateHigherRanked + ) && match self.consider_ambiguities { + true => matches!(nested_goal.result(), Ok(Certainty::Maybe(_))), + false => matches!(nested_goal.result(), Err(_)), + } + }) + }) + }); + } + + candidates + } } impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { @@ -314,11 +350,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { } fn visit_goal(&mut self, goal: &super::inspect::InspectGoal<'_, 'tcx>) -> Self::Result { - // FIXME: Throw out candidates that have no failing WC and >0 failing misc goal. - // This most likely means that the goal just didn't unify at all, e.g. a param - // candidate with an alias in it. - let candidates = goal.candidates(); - + let candidates = self.non_trivial_candidates(goal); let [candidate] = candidates.as_slice() else { return ControlFlow::Break(self.obligation.clone()); }; @@ -393,7 +425,7 @@ fn derive_cause<'tcx>( tcx.predicates_of(impl_def_id).instantiate_identity(tcx).iter().nth(idx) { cause = cause.derived_cause(parent_trait_pred, |derived| { - traits::ImplDerivedObligation(Box::new(traits::ImplDerivedObligationCause { + ObligationCauseCode::ImplDerived(Box::new(traits::ImplDerivedCause { derived, impl_or_alias_def_id: impl_def_id, impl_def_predicate_index: Some(idx), @@ -403,7 +435,7 @@ fn derive_cause<'tcx>( } } ProbeKind::TraitCandidate { source: CandidateSource::BuiltinImpl(..), result: _ } => { - cause = cause.derived_cause(parent_trait_pred, traits::BuiltinDerivedObligation); + cause = cause.derived_cause(parent_trait_pred, ObligationCauseCode::BuiltinDerived); } _ => {} }; diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 4f79f1b2aafe0..fd36b7ffd4eb4 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -12,10 +12,8 @@ use rustc_ast_ir::try_visit; use rustc_ast_ir::visit::VisitorResult; use rustc_infer::infer::resolve::EagerResolver; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_macros::extension; -use rustc_middle::infer::unify_key::ConstVariableOrigin; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{inspect, QueryResult}; use rustc_middle::traits::solve::{Certainty, Goal}; @@ -93,6 +91,7 @@ pub struct InspectCandidate<'a, 'tcx> { kind: inspect::ProbeKind<'tcx>, nested_goals: Vec<(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>)>, final_state: inspect::CanonicalState<'tcx, ()>, + impl_args: Option>>, result: QueryResult<'tcx>, shallow_certainty: Certainty, } @@ -135,7 +134,25 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { /// Instantiate the nested goals for the candidate without rolling back their /// inference constraints. This function modifies the state of the `infcx`. + /// + /// See [`Self::instantiate_nested_goals_and_opt_impl_args`] if you need the impl args too. pub fn instantiate_nested_goals(&self, span: Span) -> Vec> { + self.instantiate_nested_goals_and_opt_impl_args(span).0 + } + + /// Instantiate the nested goals for the candidate without rolling back their + /// inference constraints, and optionally the args of an impl if this candidate + /// came from a `CandidateSource::Impl`. This function modifies the state of the + /// `infcx`. + #[instrument( + level = "debug", + skip_all, + fields(goal = ?self.goal.goal, nested_goals = ?self.nested_goals) + )] + pub fn instantiate_nested_goals_and_opt_impl_args( + &self, + span: Span, + ) -> (Vec>, Option>) { let infcx = self.goal.infcx; let param_env = self.goal.goal.param_env; let mut orig_values = self.goal.orig_values.to_vec(); @@ -164,6 +181,17 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { self.final_state, ); + let impl_args = self.impl_args.map(|impl_args| { + canonical::instantiate_canonical_state( + infcx, + span, + param_env, + &mut orig_values, + impl_args, + ) + .fold_with(&mut EagerResolver::new(infcx)) + }); + if let Some(term_hack) = self.goal.normalizes_to_term_hack { // FIXME: We ignore the expected term of `NormalizesTo` goals // when computing the result of its candidates. This is @@ -171,27 +199,33 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { let _ = term_hack.constrain(infcx, span, param_env); } - instantiated_goals + let goals = instantiated_goals .into_iter() .map(|(source, goal)| match goal.predicate.kind().no_bound_vars() { Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => { let unconstrained_term = match term.unpack() { - ty::TermKind::Ty(_) => infcx - .next_ty_var(TypeVariableOrigin { param_def_id: None, span }) - .into(), - ty::TermKind::Const(ct) => infcx - .next_const_var( - ct.ty(), - ConstVariableOrigin { param_def_id: None, span }, - ) - .into(), + ty::TermKind::Ty(_) => infcx.next_ty_var(span).into(), + ty::TermKind::Const(ct) => infcx.next_const_var(ct.ty(), span).into(), }; let goal = goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term }); - let proof_tree = EvalCtxt::enter_root(infcx, GenerateProofTree::Yes, |ecx| { - ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal) - }) - .1; + // We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the + // expected term. This means that candidates which only fail due to nested goals + // and which normalize to a different term then the final result could ICE: when + // building their proof tree, the expected term was unconstrained, but when + // instantiating the candidate it is already constrained to the result of another + // candidate. + let proof_tree = infcx + .probe(|_| { + EvalCtxt::enter_root(infcx, GenerateProofTree::Yes, |ecx| { + ecx.evaluate_goal_raw( + GoalEvaluationKind::Root, + GoalSource::Misc, + goal, + ) + }) + }) + .1; InspectGoal::new( infcx, self.goal.depth + 1, @@ -200,15 +234,21 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { source, ) } - _ => InspectGoal::new( - infcx, - self.goal.depth + 1, - infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1.unwrap(), - None, - source, - ), + _ => { + // We're using a probe here as evaluating a goal could constrain + // inference variables by choosing one candidate. If we then recurse + // into another candidate who ends up with different inference + // constraints, we get an ICE if we already applied the constraints + // from the chosen candidate. + let proof_tree = infcx + .probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1) + .unwrap(); + InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source) + } }) - .collect() + .collect(); + + (goals, impl_args) } /// Visit all nested goals of this candidate, rolling back @@ -245,9 +285,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { probe: &inspect::Probe<'tcx>, ) { let mut shallow_certainty = None; + let mut impl_args = None; for step in &probe.steps { - match step { - &inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)), + match *step { + inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)), inspect::ProbeStep::NestedProbe(ref probe) => { // Nested probes have to prove goals added in their parent // but do not leak them, so we truncate the added goals @@ -257,7 +298,10 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { nested_goals.truncate(num_goals); } inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => { - assert_eq!(shallow_certainty.replace(*c), None); + assert_eq!(shallow_certainty.replace(c), None); + } + inspect::ProbeStep::RecordImplArgs { impl_args: i } => { + assert_eq!(impl_args.replace(i), None); } inspect::ProbeStep::EvaluateGoals(_) => (), } @@ -284,6 +328,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { final_state: probe.final_state, result, shallow_certainty, + impl_args, }); } } diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs index 466d0d8006018..3c5505055a443 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs @@ -242,6 +242,7 @@ enum WipProbeStep<'tcx> { EvaluateGoals(WipAddedGoalsEvaluation<'tcx>), NestedProbe(WipProbe<'tcx>), MakeCanonicalResponse { shallow_certainty: Certainty }, + RecordImplArgs { impl_args: inspect::CanonicalState<'tcx, ty::GenericArgsRef<'tcx>> }, } impl<'tcx> WipProbeStep<'tcx> { @@ -250,6 +251,9 @@ impl<'tcx> WipProbeStep<'tcx> { WipProbeStep::AddGoal(source, goal) => inspect::ProbeStep::AddGoal(source, goal), WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()), WipProbeStep::NestedProbe(probe) => inspect::ProbeStep::NestedProbe(probe.finalize()), + WipProbeStep::RecordImplArgs { impl_args } => { + inspect::ProbeStep::RecordImplArgs { impl_args } + } WipProbeStep::MakeCanonicalResponse { shallow_certainty } => { inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty } } @@ -372,7 +376,10 @@ impl<'tcx> ProofTreeBuilder<'tcx> { ( DebugSolver::GoalEvaluation(goal_evaluation), DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation), - ) => goal_evaluation.evaluation = Some(canonical_goal_evaluation), + ) => { + let prev = goal_evaluation.evaluation.replace(canonical_goal_evaluation); + assert_eq!(prev, None); + } _ => unreachable!(), } } @@ -534,6 +541,30 @@ impl<'tcx> ProofTreeBuilder<'tcx> { } } + pub(crate) fn record_impl_args( + &mut self, + infcx: &InferCtxt<'tcx>, + max_input_universe: ty::UniverseIndex, + impl_args: ty::GenericArgsRef<'tcx>, + ) { + match self.as_mut() { + Some(DebugSolver::GoalEvaluationStep(state)) => { + let impl_args = canonical::make_canonical_state( + infcx, + &state.var_values, + max_input_universe, + impl_args, + ); + state + .current_evaluation_scope() + .steps + .push(WipProbeStep::RecordImplArgs { impl_args }); + } + None => {} + _ => bug!(), + } + } + pub fn make_canonical_response(&mut self, shallow_certainty: Certainty) { match self.as_mut() { Some(DebugSolver::GoalEvaluationStep(state)) => { @@ -543,7 +574,7 @@ impl<'tcx> ProofTreeBuilder<'tcx> { .push(WipProbeStep::MakeCanonicalResponse { shallow_certainty }); } None => {} - _ => {} + _ => bug!(), } } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index b2b076e28e648..80ae4b6022dcf 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -82,7 +82,7 @@ impl<'tcx> Canonical<'tcx, Response<'tcx>> { } impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { - #[instrument(level = "debug", skip(self))] + #[instrument(level = "trace", skip(self))] fn compute_type_outlives_goal( &mut self, goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>, @@ -92,7 +92,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } - #[instrument(level = "debug", skip(self))] + #[instrument(level = "trace", skip(self))] fn compute_region_outlives_goal( &mut self, goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>, @@ -102,7 +102,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } - #[instrument(level = "debug", skip(self))] + #[instrument(level = "trace", skip(self))] fn compute_coerce_goal( &mut self, goal: Goal<'tcx, CoercePredicate<'tcx>>, @@ -117,7 +117,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { }) } - #[instrument(level = "debug", skip(self))] + #[instrument(level = "trace", skip(self))] fn compute_subtype_goal( &mut self, goal: Goal<'tcx, SubtypePredicate<'tcx>>, @@ -138,7 +138,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } } - #[instrument(level = "debug", skip(self))] + #[instrument(level = "trace", skip(self))] fn compute_well_formed_goal( &mut self, goal: Goal<'tcx, ty::GenericArg<'tcx>>, @@ -152,7 +152,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } } - #[instrument(level = "debug", skip(self))] + #[instrument(level = "trace", skip(self))] fn compute_const_evaluatable_goal( &mut self, Goal { param_env, predicate: ct }: Goal<'tcx, ty::Const<'tcx>>, @@ -189,7 +189,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } } - #[instrument(level = "debug", skip(self), ret)] + #[instrument(level = "trace", skip(self), ret)] fn compute_const_arg_has_type_goal( &mut self, goal: Goal<'tcx, (ty::Const<'tcx>, Ty<'tcx>)>, @@ -201,7 +201,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { } impl<'tcx> EvalCtxt<'_, 'tcx> { - #[instrument(level = "debug", skip(self, goals))] + #[instrument(level = "trace", skip(self, goals))] fn add_goals( &mut self, source: GoalSource, @@ -215,7 +215,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// Try to merge multiple possible ways to prove a goal, if that is not possible returns `None`. /// /// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`. - #[instrument(level = "debug", skip(self), ret)] + #[instrument(level = "trace", skip(self), ret)] fn try_merge_responses( &mut self, responses: &[CanonicalResponse<'tcx>], @@ -241,7 +241,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } /// If we fail to merge responses we flounder and return overflow or ambiguity. - #[instrument(level = "debug", skip(self), ret)] + #[instrument(level = "trace", skip(self), ret)] fn flounder(&mut self, responses: &[CanonicalResponse<'tcx>]) -> QueryResult<'tcx> { if responses.is_empty() { return Err(NoSolution); @@ -263,7 +263,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// This function is necessary in nearly all cases before matching on a type. /// Not doing so is likely to be incomplete and therefore unsound during /// coherence. - #[instrument(level = "debug", skip(self, param_env), ret)] + #[instrument(level = "trace", skip(self, param_env), ret)] fn structurally_normalize_ty( &mut self, param_env: ty::ParamEnv<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 65ef465990727..1ac1827bf1c33 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -3,11 +3,9 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{BoundVarReplacer, PlaceholderReplacer}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::at::At; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::TraitEngineExt; use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine}; -use rustc_middle::infer::unify_key::ConstVariableOrigin; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, AliasTy, Ty, TyCtxt, UniverseIndex}; use rustc_middle::ty::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; @@ -74,8 +72,7 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> { self.depth += 1; - let new_infer_ty = - infcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span: self.at.cause.span }); + let new_infer_ty = infcx.next_ty_var(self.at.cause.span); let obligation = Obligation::new( tcx, self.at.cause.clone(), @@ -120,10 +117,7 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> { self.depth += 1; - let new_infer_ct = infcx.next_const_var( - ty, - ConstVariableOrigin { param_def_id: None, span: self.at.cause.span }, - ); + let new_infer_ct = infcx.next_const_var(ty, self.at.cause.span); let obligation = Obligation::new( tcx, self.at.cause.clone(), @@ -168,7 +162,7 @@ impl<'tcx> FallibleTypeFolder> for NormalizationFolder<'_, 'tcx> { Ok(t) } - #[instrument(level = "debug", skip(self), ret)] + #[instrument(level = "trace", skip(self), ret)] fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result, Self::Error> { let infcx = self.at.infcx; debug_assert_eq!(ty, infcx.shallow_resolve(ty)); @@ -195,7 +189,7 @@ impl<'tcx> FallibleTypeFolder> for NormalizationFolder<'_, 'tcx> { } } - #[instrument(level = "debug", skip(self), ret)] + #[instrument(level = "trace", skip(self), ret)] fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result, Self::Error> { let infcx = self.at.infcx; debug_assert_eq!(ct, infcx.shallow_resolve_const(ct)); diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs index 37d5645289398..94e078f56159e 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs @@ -3,7 +3,7 @@ use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; use rustc_middle::ty; impl<'tcx> EvalCtxt<'_, 'tcx> { - #[instrument(level = "debug", skip(self), ret)] + #[instrument(level = "trace", skip(self), ret)] pub(super) fn normalize_anon_const( &mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, 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 f886c5886504c..8d5c5d2a06380 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -25,7 +25,7 @@ mod opaque_types; mod weak_types; impl<'tcx> EvalCtxt<'_, 'tcx> { - #[instrument(level = "debug", skip(self), ret)] + #[instrument(level = "trace", skip(self), ret)] pub(super) fn compute_normalizes_to_goal( &mut self, goal: Goal<'tcx, NormalizesTo<'tcx>>, @@ -59,7 +59,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { /// Normalize the given alias by at least one step. If the alias is rigid, this /// returns `NoSolution`. - #[instrument(level = "debug", skip(self), ret)] + #[instrument(level = "trace", skip(self), ret)] fn normalize_at_least_one_step( &mut self, goal: Goal<'tcx, NormalizesTo<'tcx>>, @@ -368,7 +368,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } }; let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { - ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output]) + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output]) }); let pred = tupled_inputs_and_output @@ -414,7 +414,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { )?; let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( |AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| { - ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output_ty]) + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output_ty]) }, ); @@ -576,10 +576,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`. // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't // exist. Instead, `Pointee` should be a supertrait of `Sized`. - let sized_predicate = ty::TraitRef::from_lang_item( + let sized_predicate = ty::TraitRef::new( tcx, - LangItem::Sized, - DUMMY_SP, + tcx.require_lang_item(LangItem::Sized, None), [ty::GenericArg::from(goal.predicate.self_ty())], ); // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`? @@ -898,7 +897,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { /// /// FIXME: We should merge these 3 implementations as it's likely that they otherwise /// diverge. -#[instrument(level = "debug", skip(ecx, param_env), ret)] +#[instrument(level = "trace", skip(ecx, param_env), ret)] fn fetch_eligible_assoc_item_def<'tcx>( ecx: &EvalCtxt<'_, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -921,7 +920,7 @@ fn fetch_eligible_assoc_item_def<'tcx>( let poly_trait_ref = ecx.resolve_vars_if_possible(goal_trait_ref); !poly_trait_ref.still_further_specializable() } else { - debug!(?node_item.item.def_id, "not eligible due to default"); + trace!(?node_item.item.def_id, "not eligible due to default"); false } }; diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 30ae385a8a0b7..74b3db71e78f2 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -5,7 +5,7 @@ use rustc_middle::traits::solve::{Certainty, Goal, QueryResult}; use rustc_middle::ty::{self, ProjectionPredicate}; impl<'tcx> EvalCtxt<'_, 'tcx> { - #[instrument(level = "debug", skip(self), ret)] + #[instrument(level = "trace", skip(self), ret)] pub(super) fn compute_projection_goal( &mut self, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, diff --git a/compiler/rustc_trait_selection/src/solve/search_graph.rs b/compiler/rustc_trait_selection/src/solve/search_graph.rs index a48b2f2478b0d..60362aa01da8b 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph.rs @@ -130,7 +130,7 @@ impl<'tcx> SearchGraph<'tcx> { } /// Update the stack and reached depths on cache hits. - #[instrument(level = "debug", skip(self))] + #[instrument(level = "trace", skip(self))] fn on_cache_hit(&mut self, additional_depth: usize, encountered_overflow: bool) { let reached_depth = self.stack.next_index().plus(additional_depth); if let Some(last) = self.stack.raw.last_mut() { @@ -296,6 +296,7 @@ impl<'tcx> SearchGraph<'tcx> { } self.on_cache_hit(reached_depth, encountered_overflow); + debug!("global cache hit"); return result; } @@ -315,6 +316,7 @@ impl<'tcx> SearchGraph<'tcx> { .filter(|p| !Self::stack_coinductive_from(tcx, &self.stack, p.head)) }) { + debug!("provisional cache hit"); // We have a nested goal which is already in the provisional cache, use // its result. We do not provide any usage kind as that should have been // already set correctly while computing the cache entry. diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index d2b893d6383bd..2f1b7d60df310 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -16,7 +16,7 @@ use rustc_middle::traits::{BuiltinImplSource, Reveal}; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt}; use rustc_middle::ty::{TraitPredicate, TypeVisitableExt}; -use rustc_span::{ErrorGuaranteed, DUMMY_SP}; +use rustc_span::ErrorGuaranteed; impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn self_ty(self) -> Ty<'tcx> { @@ -75,6 +75,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| { let impl_args = ecx.fresh_args_for_item(impl_def_id); + ecx.record_impl_args(impl_args); let impl_trait_ref = impl_trait_header.trait_ref.instantiate(tcx, impl_args); ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; @@ -306,7 +307,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } }; let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { - ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output]) + ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output]) }); let pred = tupled_inputs_and_output @@ -345,7 +346,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { )?; let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| { - ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output_coroutine_ty]) + ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::Sized, None), + [output_coroutine_ty], + ) }, ); @@ -1125,7 +1130,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { }, ); if let Some(def_id) = disqualifying_impl { - debug!(?def_id, ?goal, "disqualified auto-trait implementation"); + trace!(?def_id, ?goal, "disqualified auto-trait implementation"); // No need to actually consider the candidate here, // since we do that in `consider_impl_candidate`. return Some(Err(NoSolution)); @@ -1166,7 +1171,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { }) } - #[instrument(level = "debug", skip(self))] + #[instrument(level = "trace", skip(self))] pub(super) fn compute_trait_goal( &mut self, goal: Goal<'tcx, TraitPredicate<'tcx>>, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs index 9e5701ffffc60..4b5b1d77b30da 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs @@ -1,4 +1,3 @@ -use crate::infer::type_variable::TypeVariableOrigin; use crate::infer::InferCtxt; use crate::traits::{Obligation, ObligationCause, ObligationCtxt}; use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, Diag}; @@ -218,8 +217,7 @@ impl<'tcx> InferCtxt<'tcx> { let Some(trait_def_id) = trait_def_id else { continue }; // Make a fresh inference variable so we can determine what the generic parameters // of the trait are. - let var = - self.next_ty_var(TypeVariableOrigin { span: DUMMY_SP, param_def_id: None }); + let var = self.next_ty_var(DUMMY_SP); // FIXME(effects) let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]); let obligation = Obligation::new( diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 07bd209e62394..040ce450aaf93 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -10,6 +10,7 @@ use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::{extension, LintDiagnostic}; +use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt}; use rustc_parse_format::{ParseMode, Parser, Piece, Position}; @@ -127,9 +128,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { flags.push((sym::ItemContext, enclosure)); match obligation.cause.code() { - ObligationCauseCode::BuiltinDerivedObligation(..) - | ObligationCauseCode::ImplDerivedObligation(..) - | ObligationCauseCode::WellFormedDerivedObligation(..) => {} + ObligationCauseCode::BuiltinDerived(..) + | ObligationCauseCode::ImplDerived(..) + | ObligationCauseCode::WellFormedDerived(..) => {} _ => { // this is a "direct", user-specified, rather than derived, // obligation. @@ -165,7 +166,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { )); } - for param in generics.params.iter() { + for param in generics.own_params.iter() { let value = match param.kind { GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { args[param.index as usize].to_string() @@ -350,12 +351,14 @@ impl IgnoredDiagnosticOption { option_name: &'static str, ) { if let (Some(new_item), Some(old_item)) = (new, old) { - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id.expect_local()), - new_item, - IgnoredDiagnosticOption { span: new_item, prev_span: old_item, option_name }, - ); + if let Some(item_def_id) = item_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id), + new_item, + IgnoredDiagnosticOption { span: new_item, prev_span: old_item, option_name }, + ); + } } } } @@ -499,12 +502,14 @@ impl<'tcx> OnUnimplementedDirective { } if is_diagnostic_namespace_variant { - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id.expect_local()), - vec![item.span()], - MalformedOnUnimplementedAttrLint::new(item.span()), - ); + if let Some(def_id) = item_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(def_id), + vec![item.span()], + MalformedOnUnimplementedAttrLint::new(item.span()), + ); + } } else { // nothing found tcx.dcx().emit_err(NoValueInOnUnimplemented { span: item.span() }); @@ -637,30 +642,38 @@ impl<'tcx> OnUnimplementedDirective { AttrArgs::Eq(span, AttrArgsEq::Hir(expr)) => span.to(expr.span), }; - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id.expect_local()), - report_span, - MalformedOnUnimplementedAttrLint::new(report_span), - ); + if let Some(item_def_id) = item_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id), + report_span, + MalformedOnUnimplementedAttrLint::new(report_span), + ); + } Ok(None) } } else if is_diagnostic_namespace_variant { match &attr.kind { AttrKind::Normal(p) if !matches!(p.item.args, AttrArgs::Empty) => { - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id.expect_local()), - attr.span, - MalformedOnUnimplementedAttrLint::new(attr.span), - ); + if let Some(item_def_id) = item_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id), + attr.span, + MalformedOnUnimplementedAttrLint::new(attr.span), + ); + } + } + _ => { + if let Some(item_def_id) = item_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id), + attr.span, + MissingOptionsForOnUnimplementedAttr, + ) + } } - _ => tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id.expect_local()), - attr.span, - MissingOptionsForOnUnimplementedAttr, - ), }; Ok(None) @@ -789,12 +802,14 @@ impl<'tcx> OnUnimplementedFormatString { || format_spec.precision_span.is_some() || format_spec.fill_span.is_some()) { - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id.expect_local()), - self.span, - InvalidFormatSpecifier, - ); + if let Some(item_def_id) = item_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id), + self.span, + InvalidFormatSpecifier, + ); + } } match a.position { Position::ArgumentNamed(s) => { @@ -807,18 +822,20 @@ impl<'tcx> OnUnimplementedFormatString { () } // So is `{A}` if A is a type parameter - s if generics.params.iter().any(|param| param.name == s) => (), + s if generics.own_params.iter().any(|param| param.name == s) => (), s => { if self.is_diagnostic_namespace_variant { - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id.expect_local()), - self.span, - UnknownFormatParameterForOnUnimplementedAttr { - argument_name: s, - trait_name, - }, - ); + if let Some(item_def_id) = item_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id), + self.span, + UnknownFormatParameterForOnUnimplementedAttr { + argument_name: s, + trait_name, + }, + ); + } } else { result = Err(struct_span_code_err!( tcx.dcx(), @@ -840,12 +857,14 @@ impl<'tcx> OnUnimplementedFormatString { // `{:1}` and `{}` are not to be used Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => { if self.is_diagnostic_namespace_variant { - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id.expect_local()), - self.span, - DisallowedPositionalArgument, - ); + if let Some(item_def_id) = item_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id), + self.span, + DisallowedPositionalArgument, + ); + } } else { let reported = struct_span_code_err!( tcx.dcx(), @@ -868,12 +887,14 @@ impl<'tcx> OnUnimplementedFormatString { // so that users are aware that something is not correct for e in parser.errors { if self.is_diagnostic_namespace_variant { - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(item_def_id.expect_local()), - self.span, - WrappedParserError { description: e.description, label: e.label }, - ); + if let Some(item_def_id) = item_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(item_def_id), + self.span, + WrappedParserError { description: e.description, label: e.label }, + ); + } } else { let reported = struct_span_code_err!(tcx.dcx(), self.span, E0231, "{}", e.description,).emit(); @@ -895,7 +916,7 @@ impl<'tcx> OnUnimplementedFormatString { let trait_str = tcx.def_path_str(trait_ref.def_id); let generics = tcx.generics_of(trait_ref.def_id); let generic_map = generics - .params + .own_params .iter() .filter_map(|param| { let value = match param.kind { 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 3d2574ac92b66..ea1752a6e982c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -7,7 +7,7 @@ use super::{ use crate::errors; use crate::infer::InferCtxt; -use crate::traits::{ImplDerivedObligationCause, NormalizeExt, ObligationCtxt}; +use crate::traits::{ImplDerivedCause, NormalizeExt, ObligationCtxt}; use hir::def::CtorOf; use rustc_data_structures::fx::FxHashSet; @@ -24,7 +24,6 @@ use rustc_hir::is_range_literal; use rustc_hir::lang_items::LangItem; use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node}; use rustc_infer::infer::error_reporting::TypeErrCtxt; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk}; use rustc_macros::extension; use rustc_middle::hir::map; @@ -46,7 +45,9 @@ use std::iter; use crate::infer::InferCtxtExt as _; use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths}; +use rustc_middle::ty::print::{ + with_forced_trimmed_paths, with_no_trimmed_paths, PrintTraitPredicateExt as _, +}; use itertools::EitherOrBoth; use itertools::Itertools; @@ -456,8 +457,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> bool { let mut code = obligation.cause.code(); - if let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, call_hir_id, .. } = - code + if let ObligationCauseCode::FunctionArg { arg_hir_id, call_hir_id, .. } = code && let Some(typeck_results) = &self.typeck_results && let hir::Node::Expr(expr) = self.tcx.hir_node(*arg_hir_id) && let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr) @@ -539,10 +539,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.tcx, obligation.cause.clone(), obligation.param_env, - ty::TraitRef::from_lang_item( + ty::TraitRef::new( self.tcx, - hir::LangItem::Sized, - obligation.cause.span, + self.tcx.require_lang_item( + hir::LangItem::Sized, + Some(obligation.cause.span), + ), [base_ty], ), ); @@ -847,7 +849,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .collect::>() .join(", "); - if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArgumentObligation { .. }) + if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArg { .. }) && obligation.cause.span.can_be_used_for_suggestions() { // When the obligation error has been ensured to have been caused by @@ -981,8 +983,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false }; let ty::Param(param) = inner_ty.kind() else { return false }; - let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = - obligation.cause.code() + let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code() else { return false; }; @@ -1205,9 +1206,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let span = obligation.cause.span; let code = match obligation.cause.code() { - ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => parent_code, - c @ ObligationCauseCode::ItemObligation(_) - | c @ ObligationCauseCode::ExprItemObligation(..) => c, + ObligationCauseCode::FunctionArg { parent_code, .. } => parent_code, + // FIXME(compiler-errors): This is kind of a mess, but required for obligations + // that come from a path expr to affect the *call* expr. + c @ ObligationCauseCode::WhereClauseInExpr(_, _, hir_id, _) + if self.tcx.hir().span(*hir_id).lo() == span.lo() => + { + c + } c if matches!( span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(DesugaringKind::ForLoop) @@ -1263,8 +1269,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref); let (ref_inner_ty_satisfies_pred, ref_inner_ty_mut) = - if let ObligationCauseCode::ItemObligation(_) - | ObligationCauseCode::ExprItemObligation(..) = obligation.cause.code() + if let ObligationCauseCode::WhereClauseInExpr(..) = obligation.cause.code() && let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind() { ( @@ -1402,12 +1407,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { return false; }; - if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code { + if let ObligationCauseCode::ImplDerived(cause) = &*code { try_borrowing(cause.derived.parent_trait_pred, &[]) - } else if let ObligationCauseCode::BindingObligation(_, _) - | ObligationCauseCode::ItemObligation(_) - | ObligationCauseCode::ExprItemObligation(..) - | ObligationCauseCode::ExprBindingObligation(..) = code + } else if let ObligationCauseCode::WhereClause(..) + | ObligationCauseCode::WhereClauseInExpr(..) = code { try_borrowing(poly_trait_pred, &never_suggest_borrow) } else { @@ -1645,10 +1648,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { err: &mut Diag<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) { - let points_at_arg = matches!( - obligation.cause.code(), - ObligationCauseCode::FunctionArgumentObligation { .. }, - ); + let points_at_arg = + matches!(obligation.cause.code(), ObligationCauseCode::FunctionArg { .. },); let span = obligation.cause.span; if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { @@ -1893,8 +1894,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ty::Tuple(inputs) if infcx.tcx.is_fn_trait(trait_ref.def_id) => { infcx.tcx.mk_fn_sig( *inputs, - infcx - .next_ty_var(TypeVariableOrigin { span: DUMMY_SP, param_def_id: None }), + infcx.next_ty_var(DUMMY_SP), false, hir::Unsafety::Normal, abi::Abi::Rust, @@ -1902,7 +1902,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } _ => infcx.tcx.mk_fn_sig( [inputs], - infcx.next_ty_var(TypeVariableOrigin { span: DUMMY_SP, param_def_id: None }), + infcx.next_ty_var(DUMMY_SP), false, hir::Unsafety::Normal, abi::Abi::Rust, @@ -1955,7 +1955,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { found: Ty<'tcx>, param_env: ty::ParamEnv<'tcx>, ) { - let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = cause else { + let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = cause else { return; }; let ty::FnPtr(expected) = expected.kind() else { @@ -2106,10 +2106,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { cause: &ObligationCauseCode<'tcx>, err: &mut Diag<'tcx>, ) { - // First, look for an `ExprBindingObligation`, which means we can get + // First, look for an `WhereClauseInExpr`, which means we can get // the uninstantiated predicate list of the called function. And check // that the predicate that we failed to satisfy is a `Fn`-like trait. - if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = cause + if let ObligationCauseCode::WhereClauseInExpr(def_id, _, _, idx) = cause && let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx) && let Some(pred) = predicates.predicates.get(*idx) && let ty::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder() @@ -2263,10 +2263,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { while let Some(code) = next_code { debug!(?code); match code { - ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => { + ObligationCauseCode::FunctionArg { parent_code, .. } => { next_code = Some(parent_code); } - ObligationCauseCode::ImplDerivedObligation(cause) => { + ObligationCauseCode::ImplDerived(cause) => { let ty = cause.derived.parent_trait_pred.skip_binder().self_ty(); debug!( parent_trait_ref = ?cause.derived.parent_trait_pred, @@ -2295,8 +2295,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { next_code = Some(&cause.derived.parent_code); } - ObligationCauseCode::WellFormedDerivedObligation(derived_obligation) - | ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) => { + ObligationCauseCode::WellFormedDerived(derived_obligation) + | ObligationCauseCode::BuiltinDerived(derived_obligation) => { let ty = derived_obligation.parent_trait_pred.skip_binder().self_ty(); debug!( parent_trait_ref = ?derived_obligation.parent_trait_pred, @@ -2721,7 +2721,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::MethodReceiver | ObligationCauseCode::ReturnNoExpression | ObligationCauseCode::UnifyReceiver(..) - | ObligationCauseCode::MiscObligation + | ObligationCauseCode::Misc | ObligationCauseCode::WellFormed(..) | ObligationCauseCode::MatchImpl(..) | ObligationCauseCode::ReturnValue(_) @@ -2750,13 +2750,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ObligationCauseCode::TupleElem => { err.note("only the last element of a tuple may have a dynamically sized type"); } - ObligationCauseCode::ItemObligation(_) - | ObligationCauseCode::ExprItemObligation(..) => { - // We hold the `DefId` of the item introducing the obligation, but displaying it - // doesn't add user usable information. It always point at an associated item. - } - ObligationCauseCode::BindingObligation(item_def_id, span) - | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..) => { + ObligationCauseCode::WhereClause(item_def_id, span) + | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..) + if !span.is_dummy() => + { let item_name = tcx.def_path_str(item_def_id); let short_item_name = with_forced_trimmed_paths!(tcx.def_path_str(item_def_id)); let mut multispan = MultiSpan::from(span); @@ -2799,7 +2796,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // Check if this is an implicit bound, even in foreign crates. if tcx .generics_of(item_def_id) - .params + .own_params .iter() .any(|param| tcx.def_span(param.def_id) == span) { @@ -2887,6 +2884,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { err.help(help); } } + ObligationCauseCode::WhereClause(..) | ObligationCauseCode::WhereClauseInExpr(..) => { + // We hold the `DefId` of the item introducing the obligation, but displaying it + // doesn't add user usable information. It always point at an associated item. + } ObligationCauseCode::Coercion { source, target } => { let source = tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut long_ty_file); @@ -3177,7 +3178,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ObligationCauseCode::SharedStatic => { err.note("shared static variables must have a type that implements `Sync`"); } - ObligationCauseCode::BuiltinDerivedObligation(ref data) => { + ObligationCauseCode::BuiltinDerived(ref data) => { let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); let ty = parent_trait_ref.skip_binder().self_ty(); if parent_trait_ref.references_error() { @@ -3192,8 +3193,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let is_upvar_tys_infer_tuple = if !matches!(ty.kind(), ty::Tuple(..)) { false } else { - if let ObligationCauseCode::BuiltinDerivedObligation(data) = &*data.parent_code - { + if let ObligationCauseCode::BuiltinDerived(data) = &*data.parent_code { let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); let nested_ty = parent_trait_ref.skip_binder().self_ty(); @@ -3299,7 +3299,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }); } } - ObligationCauseCode::ImplDerivedObligation(ref data) => { + ObligationCauseCode::ImplDerived(ref data) => { let mut parent_trait_pred = self.resolve_vars_if_possible(data.derived.parent_trait_pred); let parent_def_id = parent_trait_pred.def_id(); @@ -3369,9 +3369,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if is_auto_trait { // We don't want to point at the ADT saying "required because it appears within // the type `X`", like we would otherwise do in test `supertrait-auto-trait.rs`. - while let ObligationCauseCode::BuiltinDerivedObligation(derived) = - &*data.parent_code - { + while let ObligationCauseCode::BuiltinDerived(derived) = &*data.parent_code { let child_trait_ref = self.resolve_vars_if_possible(derived.parent_trait_pred); let child_def_id = child_trait_ref.def_id(); @@ -3383,7 +3381,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { parent_trait_pred = child_trait_ref; } } - while let ObligationCauseCode::ImplDerivedObligation(child) = &*data.parent_code { + while let ObligationCauseCode::ImplDerived(child) = &*data.parent_code { // Skip redundant recursive obligation notes. See `ui/issue-20413.rs`. let child_trait_pred = self.resolve_vars_if_possible(child.derived.parent_trait_pred); @@ -3424,7 +3422,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) }); } - ObligationCauseCode::WellFormedDerivedObligation(ref data) => { + ObligationCauseCode::WellFormedDerived(ref data) => { let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); let parent_predicate = parent_trait_ref; // #74711: avoid a stack overflow @@ -3460,11 +3458,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { format!("required by a bound on the type alias `{}`", tcx.item_name(def_id)), ); } - ObligationCauseCode::FunctionArgumentObligation { - arg_hir_id, - call_hir_id, - ref parent_code, - .. + ObligationCauseCode::FunctionArg { + arg_hir_id, call_hir_id, ref parent_code, .. } => { self.note_function_argument_obligation( body_id, @@ -3487,7 +3482,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) }); } - ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => { + ObligationCauseCode::CompareImplItem { trait_item_def_id, kind, .. } => { let item_name = tcx.item_name(trait_item_def_id); let msg = format!( "the requirement `{predicate}` appears on the `impl`'s {kind} \ @@ -3696,7 +3691,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { err: &mut Diag<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, ) { - if let ObligationCauseCode::ImplDerivedObligation(_) = obligation.cause.code() + if let ObligationCauseCode::ImplDerived(_) = obligation.cause.code() && self .tcx .is_diagnostic_item(sym::SliceIndex, trait_pred.skip_binder().trait_ref.def_id) @@ -3813,7 +3808,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // to an associated type (as seen from `trait_pred`) in the predicate. Like in // trait_pred `S: Sum<::Item>` and predicate `i32: Sum<&()>` let mut type_diffs = vec![]; - if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code + if let ObligationCauseCode::WhereClauseInExpr(def_id, _, _, idx) = parent_code && let Some(node_args) = typeck_results.node_args_opt(call_hir_id) && let where_clauses = self.tcx.predicates_of(def_id).instantiate(self.tcx, node_args) @@ -4046,10 +4041,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let node = tcx.hir_node_by_def_id(hir.get_parent_item(expr.hir_id).def_id); let pred = ty::Binder::dummy(ty::TraitPredicate { - trait_ref: ty::TraitRef::from_lang_item( + trait_ref: ty::TraitRef::new( tcx, - LangItem::Clone, - span, + tcx.require_lang_item(LangItem::Clone, Some(span)), [*ty], ), polarity: ty::PredicatePolarity::Positive, @@ -4263,7 +4257,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { continue; }; - let origin = TypeVariableOrigin { param_def_id: None, span }; // Make `Self` be equivalent to the type of the call chain // expression we're looking at now, so that we can tell what // for example `Iterator::Item` is at this point in the chain. @@ -4277,7 +4270,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // This will hold the resolved type of the associated type, if the // current expression implements the trait that associated type is // in. For example, this would be what `Iterator::Item` is here. - let ty = self.infcx.next_ty_var(origin); + let ty = self.infcx.next_ty_var(span); // This corresponds to `::Item = _`. let projection = ty::Binder::dummy(ty::PredicateKind::Clause( ty::ClauseKind::Projection(ty::ProjectionPredicate { @@ -4323,8 +4316,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ) { // We can only suggest the slice coersion for function and binary operation arguments, // since the suggestion would make no sense in turbofish or call - let (ObligationCauseCode::BinOp { .. } - | ObligationCauseCode::FunctionArgumentObligation { .. }) = obligation.cause.code() + let (ObligationCauseCode::BinOp { .. } | ObligationCauseCode::FunctionArg { .. }) = + obligation.cause.code() else { return; }; @@ -4410,7 +4403,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { return; } - if let ObligationCauseCode::FunctionArgumentObligation { + if let ObligationCauseCode::FunctionArg { call_hir_id, arg_hir_id, parent_code: _, @@ -4970,7 +4963,7 @@ fn point_at_assoc_type_restriction( trait_name: &str, predicate: ty::Predicate<'_>, generics: &hir::Generics<'_>, - data: &ImplDerivedObligationCause<'_>, + data: &ImplDerivedCause<'_>, ) { let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() else { return; 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 e50cb2af4b857..08ffe37b8b4d0 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 @@ -6,7 +6,6 @@ use crate::errors::{ AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, }; use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; -use crate::infer::type_variable::TypeVariableOrigin; use crate::infer::InferCtxtExt as _; use crate::infer::{self, InferCtxt}; use crate::traits::error_reporting::infer_ctxt_ext::InferCtxtExt; @@ -38,7 +37,10 @@ use rustc_middle::traits::SignatureMismatchData; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::{BottomUpFolder, TypeFolder, TypeSuperFoldable}; -use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print}; +use rustc_middle::ty::print::{ + with_forced_trimmed_paths, FmtPrinter, Print, PrintTraitPredicateExt as _, + PrintTraitRefExt as _, +}; use rustc_middle::ty::{ self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitableExt, @@ -392,7 +394,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - if let ObligationCauseCode::CompareImplItemObligation { + if let ObligationCauseCode::CompareImplItem { impl_item_def_id, trait_item_def_id, kind: _, @@ -1018,7 +1020,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { if let Some((_, Some(parent))) = obligation.cause.code().parent() { // If we have a derived obligation, then the parent will be a `AsyncFn*` goal. trait_ref = parent.to_poly_trait_ref(); - } else if let &ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = + } else if let &ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code() && let Some(typeck_results) = &self.typeck_results && let ty::Closure(closure_def_id, _) | ty::CoroutineClosure(closure_def_id, _) = @@ -1105,8 +1107,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, ) -> Result<(), ErrorGuaranteed> { - if let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = - obligation.cause.code() + if let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code() && let Node::Expr(arg) = self.tcx.hir_node(*arg_hir_id) && let arg = arg.peel_borrows() && let hir::ExprKind::Path(hir::QPath::Resolved( @@ -1505,13 +1506,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } match error.code { - FulfillmentErrorCode::SelectionError(ref selection_error) => self - .report_selection_error( - error.obligation.clone(), - &error.root_obligation, - selection_error, - ), - FulfillmentErrorCode::ProjectionError(ref e) => { + FulfillmentErrorCode::Select(ref selection_error) => self.report_selection_error( + error.obligation.clone(), + &error.root_obligation, + selection_error, + ), + FulfillmentErrorCode::Project(ref e) => { self.report_projection_error(&error.obligation, e) } FulfillmentErrorCode::Ambiguity { overflow: None } => { @@ -1520,7 +1520,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => { self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit) } - FulfillmentErrorCode::SubtypeError(ref expected_found, ref err) => self + FulfillmentErrorCode::Subtype(ref expected_found, ref err) => self .report_mismatched_types( &error.obligation.cause, expected_found.expected, @@ -1528,7 +1528,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { *err, ) .emit(), - FulfillmentErrorCode::ConstEquateError(ref expected_found, ref err) => { + FulfillmentErrorCode::ConstEquate(ref expected_found, ref err) => { let mut diag = self.report_mismatched_consts( &error.obligation.cause, expected_found.expected, @@ -1536,10 +1536,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { *err, ); let code = error.obligation.cause.code().peel_derives().peel_match_impls(); - if let ObligationCauseCode::BindingObligation(..) - | ObligationCauseCode::ItemObligation(..) - | ObligationCauseCode::ExprBindingObligation(..) - | ObligationCauseCode::ExprItemObligation(..) = code + if let ObligationCauseCode::WhereClause(..) + | ObligationCauseCode::WhereClauseInExpr(..) = code { self.note_obligation_cause_code( error.obligation.cause.body_id, @@ -1613,11 +1611,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let is_normalized_term_expected = !matches!( obligation.cause.code().peel_derives(), - ObligationCauseCode::ItemObligation(_) - | ObligationCauseCode::BindingObligation(_, _) - | ObligationCauseCode::ExprItemObligation(..) - | ObligationCauseCode::ExprBindingObligation(..) - | ObligationCauseCode::Coercion { .. } + |ObligationCauseCode::WhereClause(..)| ObligationCauseCode::WhereClauseInExpr( + .. + ) | ObligationCauseCode::Coercion { .. } ); let (expected, actual) = if is_normalized_term_expected { @@ -2213,7 +2209,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { code: &ObligationCauseCode<'tcx>, ) -> Option<(Ty<'tcx>, Option)> { match code { - ObligationCauseCode::BuiltinDerivedObligation(data) => { + ObligationCauseCode::BuiltinDerived(data) => { let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); match self.get_parent_trait_ref(&data.parent_code) { Some(t) => Some(t), @@ -2225,7 +2221,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } } - ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => { + ObligationCauseCode::FunctionArg { parent_code, .. } => { self.get_parent_trait_ref(parent_code) } _ => None, @@ -2448,8 +2444,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - if let ObligationCauseCode::ItemObligation(def_id) - | ObligationCauseCode::ExprItemObligation(def_id, ..) = *obligation.cause.code() + if let ObligationCauseCode::WhereClause(def_id, _) + | ObligationCauseCode::WhereClauseInExpr(def_id, ..) = *obligation.cause.code() { self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); } @@ -2826,9 +2822,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { if let ty::Param(_) = *ty.kind() { let infcx = self.infcx; - *self.var_map.entry(ty).or_insert_with(|| { - infcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span: DUMMY_SP }) - }) + *self.var_map.entry(ty).or_insert_with(|| infcx.next_ty_var(DUMMY_SP)) } else { ty.super_fold_with(self) } @@ -2886,12 +2880,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { else { return; }; - let (ObligationCauseCode::BindingObligation(item_def_id, span) - | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..)) = + let (ObligationCauseCode::WhereClause(item_def_id, span) + | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)) = *obligation.cause.code().peel_derives() else { return; }; + if span.is_dummy() { + return; + } debug!(?pred, ?item_def_id, ?span); let (Some(node), true) = ( @@ -3007,7 +3004,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { obligated_types: &mut Vec>, cause_code: &ObligationCauseCode<'tcx>, ) -> bool { - if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code { + if let ObligationCauseCode::BuiltinDerived(ref data) = cause_code { let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); let self_ty = parent_trait_ref.skip_binder().self_ty(); if obligated_types.iter().any(|ot| ot == &self_ty) { @@ -3184,10 +3181,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ObligationCauseCode::RustCall => { err.primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument"); } - ObligationCauseCode::BindingObligation(def_id, _) - | ObligationCauseCode::ItemObligation(def_id) - if self.tcx.is_fn_trait(*def_id) => - { + ObligationCauseCode::WhereClause(def_id, _) if self.tcx.is_fn_trait(*def_id) => { err.code(E0059); err.primary_message(format!( "type parameter to bare `{}` trait must be a tuple", @@ -3443,8 +3437,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self.dcx().try_steal_replace_and_emit_err(self.tcx.def_span(def_id), StashKey::Cycle, err) } - // FIXME(@lcnr): This function could be changed to trait `TraitRef` directly - // instead of using a `Binder`. fn report_signature_mismatch_error( &self, obligation: &PredicateObligation<'tcx>, @@ -3576,7 +3568,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { match self.tcx.sess.source_map().span_to_snippet(const_span) { Ok(snippet) => { let code = format!("[(); {snippet}{cast}]:"); - let def_id = if let ObligationCauseCode::CompareImplItemObligation { + let def_id = if let ObligationCauseCode::CompareImplItem { trait_item_def_id, .. } = obligation.cause.code() diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 1f10cb715430d..e3497c646dbde 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -411,7 +411,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty::PredicateKind::ObjectSafe(trait_def_id) => { if !self.selcx.tcx().check_is_object_safe(trait_def_id) { - ProcessResult::Error(FulfillmentErrorCode::SelectionError(Unimplemented)) + ProcessResult::Error(FulfillmentErrorCode::Select(Unimplemented)) } else { ProcessResult::Changed(vec![]) } @@ -435,7 +435,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ty, ) { Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())), - Err(_) => ProcessResult::Error(FulfillmentErrorCode::SelectionError( + Err(_) => ProcessResult::Error(FulfillmentErrorCode::Select( SelectionError::Unimplemented, )), } @@ -493,10 +493,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { Ok(Err(err)) => { let expected_found = ExpectedFound::new(subtype.a_is_expected, subtype.a, subtype.b); - ProcessResult::Error(FulfillmentErrorCode::SubtypeError( - expected_found, - err, - )) + ProcessResult::Error(FulfillmentErrorCode::Subtype(expected_found, err)) } } } @@ -516,10 +513,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { Ok(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)), Ok(Err(err)) => { let expected_found = ExpectedFound::new(false, coerce.a, coerce.b); - ProcessResult::Error(FulfillmentErrorCode::SubtypeError( - expected_found, - err, - )) + ProcessResult::Error(FulfillmentErrorCode::Subtype(expected_found, err)) } } } @@ -542,7 +536,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { Err( e @ NotConstEvaluatable::MentionsParam | e @ NotConstEvaluatable::Error(_), - ) => ProcessResult::Error(FulfillmentErrorCode::SelectionError( + ) => ProcessResult::Error(FulfillmentErrorCode::Select( SelectionError::NotConstEvaluatable(e), )), } @@ -638,7 +632,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ProcessResult::Changed(mk_pending(inf_ok.into_obligations())) } Err(err) => { - ProcessResult::Error(FulfillmentErrorCode::ConstEquateError( + ProcessResult::Error(FulfillmentErrorCode::ConstEquate( ExpectedFound::new(true, c1, c2), err, )) @@ -646,13 +640,11 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } } (Err(ErrorHandled::Reported(reported, _)), _) - | (_, Err(ErrorHandled::Reported(reported, _))) => { - ProcessResult::Error(FulfillmentErrorCode::SelectionError( - SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error( - reported.into(), - )), - )) - } + | (_, Err(ErrorHandled::Reported(reported, _))) => ProcessResult::Error( + FulfillmentErrorCode::Select(SelectionError::NotConstEvaluatable( + NotConstEvaluatable::Error(reported.into()), + )), + ), (Err(ErrorHandled::TooGeneric(_)), _) | (_, Err(ErrorHandled::TooGeneric(_))) => { if c1.has_non_region_infer() || c2.has_non_region_infer() { @@ -660,7 +652,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { } else { // Two different constants using generic parameters ~> error. let expected_found = ExpectedFound::new(true, c1, c2); - ProcessResult::Error(FulfillmentErrorCode::ConstEquateError( + ProcessResult::Error(FulfillmentErrorCode::ConstEquate( expected_found, TypeError::ConstMismatch(expected_found), )) @@ -741,7 +733,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { Err(selection_err) => { debug!("selecting trait at depth {} yielded Err", obligation.recursion_depth); - ProcessResult::Error(FulfillmentErrorCode::SelectionError(selection_err)) + ProcessResult::Error(FulfillmentErrorCode::Select(selection_err)) } } } @@ -793,7 +785,7 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { project_obligation.with(tcx, project_obligation.predicate), ])), ProjectAndUnifyResult::MismatchedProjectionTypes(e) => { - ProcessResult::Error(FulfillmentErrorCode::ProjectionError(e)) + ProcessResult::Error(FulfillmentErrorCode::Project(e)) } } } diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 93f9c2333f0c0..da2b004761fc3 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -10,7 +10,7 @@ use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_infer::traits::query::NoSolution; use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError}; -use rustc_middle::ty::{self, AdtDef, GenericArg, List, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::DUMMY_SP; use super::outlives_bounds::InferCtxtExt; @@ -129,7 +129,7 @@ pub fn all_fields_implement_trait<'tcx>( param_env: ty::ParamEnv<'tcx>, self_type: Ty<'tcx>, adt: AdtDef<'tcx>, - args: &'tcx List>, + args: ty::GenericArgsRef<'tcx>, parent_cause: ObligationCause<'tcx>, lang_item: LangItem, ) -> Result<(), Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>> { diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 0e15dd275371b..75e43bc8f5d9e 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -18,7 +18,8 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::query::Providers; use rustc_middle::ty::{ - self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, + self, EarlyBinder, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeSuperVisitable, + TypeVisitable, TypeVisitor, }; use rustc_middle::ty::{GenericArg, GenericArgs}; use rustc_middle::ty::{ToPredicate, TypeVisitableExt}; @@ -397,7 +398,7 @@ pub fn object_safety_violations_for_assoc_item( // Associated types can only be object safe if they have `Self: Sized` bounds. ty::AssocKind::Type => { if !tcx.features().generic_associated_types_extended - && !tcx.generics_of(item.def_id).params.is_empty() + && !tcx.generics_of(item.def_id).own_params.is_empty() && !item.is_impl_trait_in_trait() { vec![ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span)] diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 116e17c7e432f..f092f42dacf9a 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -13,12 +13,12 @@ use super::Selection; use super::SelectionContext; use super::SelectionError; use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey}; +use rustc_infer::traits::ObligationCauseCode; use rustc_middle::traits::BuiltinImplSource; use rustc_middle::traits::ImplSource; use rustc_middle::traits::ImplSourceUserDefinedData; use crate::errors::InherentProjectionNormalizationOverflow; -use crate::infer::type_variable::TypeVariableOrigin; use crate::infer::{BoundRegionConversionTime, InferOk}; use crate::traits::normalize::normalize_with_depth; use crate::traits::normalize::normalize_with_depth_to; @@ -521,10 +521,7 @@ fn normalize_to_error<'a, 'tcx>( predicate: trait_ref.to_predicate(selcx.tcx()), }; let tcx = selcx.infcx.tcx; - let new_value = selcx.infcx.next_ty_var(TypeVariableOrigin { - param_def_id: None, - span: tcx.def_span(projection_ty.def_id), - }); + let new_value = selcx.infcx.next_ty_var(tcx.def_span(projection_ty.def_id)); Normalized { value: new_value, obligations: vec![trait_obligation] } } @@ -576,11 +573,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( // cause code, inherent projections will be printed with identity instantiation in // diagnostics which is not ideal. // Consider creating separate cause codes for this specific situation. - if span.is_dummy() { - super::ItemObligation(alias_ty.def_id) - } else { - super::BindingObligation(alias_ty.def_id, span) - }, + ObligationCauseCode::WhereClause(alias_ty.def_id, span), ); obligations.push(Obligation::with_depth( @@ -977,9 +970,12 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // // NOTE: This should be kept in sync with the similar code in // `rustc_ty_utils::instance::resolve_associated_item()`. - let node_item = - specialization_graph::assoc_def(selcx.tcx(), impl_data.impl_def_id, obligation.predicate.def_id) - .map_err(|ErrorGuaranteed { .. }| ())?; + let node_item = specialization_graph::assoc_def( + selcx.tcx(), + impl_data.impl_def_id, + obligation.predicate.def_id, + ) + .map_err(|ErrorGuaranteed { .. }| ())?; if node_item.is_final() { // Non-specializable items are always projectable. @@ -1022,7 +1018,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( lang_items.async_fn_trait(), lang_items.async_fn_mut_trait(), lang_items.async_fn_once_trait(), - ].contains(&Some(trait_ref.def_id)) + ] + .contains(&Some(trait_ref.def_id)) { true } else if lang_items.async_fn_kind_helper() == Some(trait_ref.def_id) { @@ -1035,7 +1032,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( true } else { obligation.predicate.args.type_at(0).to_opt_closure_kind().is_some() - && obligation.predicate.args.type_at(1).to_opt_closure_kind().is_some() + && obligation.predicate.args.type_at(1).to_opt_closure_kind().is_some() } } else if lang_items.discriminant_kind_trait() == Some(trait_ref.def_id) { match self_ty.kind() { @@ -1162,12 +1159,20 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // Otherwise, type parameters, opaques, and unnormalized projections have // unit metadata if they're known (e.g. by the param_env) to be sized. ty::Param(_) | ty::Alias(..) - if self_ty != tail || selcx.infcx.predicate_must_hold_modulo_regions( - &obligation.with( - selcx.tcx(), - ty::TraitRef::from_lang_item(selcx.tcx(), LangItem::Sized, obligation.cause.span(),[self_ty]), - ), - ) => + if self_ty != tail + || selcx.infcx.predicate_must_hold_modulo_regions( + &obligation.with( + selcx.tcx(), + ty::TraitRef::new( + selcx.tcx(), + selcx.tcx().require_lang_item( + LangItem::Sized, + Some(obligation.cause.span()), + ), + [self_ty], + ), + ), + ) => { true } @@ -1230,7 +1235,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( obligation.cause.span, format!("Cannot project an associated type from `{impl_source:?}`"), ); - return Err(()) + return Err(()); } }; @@ -1559,10 +1564,9 @@ fn confirm_builtin_candidate<'cx, 'tcx>( // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`. // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't // exist. Instead, `Pointee` should be a supertrait of `Sized`. - let sized_predicate = ty::TraitRef::from_lang_item( + let sized_predicate = ty::TraitRef::new( tcx, - LangItem::Sized, - obligation.cause.span(), + tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span())), [self_ty], ); obligations.push(obligation.with(tcx, sized_predicate)); @@ -2117,22 +2121,16 @@ fn assoc_ty_own_obligations<'cx, 'tcx>( let nested_cause = if matches!( obligation.cause.code(), - super::CompareImplItemObligation { .. } - | super::CheckAssociatedTypeBounds { .. } - | super::AscribeUserTypeProvePredicate(..) + ObligationCauseCode::CompareImplItem { .. } + | ObligationCauseCode::CheckAssociatedTypeBounds { .. } + | ObligationCauseCode::AscribeUserTypeProvePredicate(..) ) { obligation.cause.clone() - } else if span.is_dummy() { - ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - super::ItemObligation(obligation.predicate.def_id), - ) } else { ObligationCause::new( obligation.cause.span, obligation.cause.body_id, - super::BindingObligation(obligation.predicate.def_id, span), + ObligationCauseCode::WhereClause(obligation.predicate.def_id, span), ) }; nested.push(Obligation::with_depth( diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs index 279d96dec728c..e9948bf1f7158 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs @@ -34,7 +34,9 @@ where } } -pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable> + Lift<'tcx> + Copy { +pub trait Normalizable<'tcx>: + fmt::Debug + TypeFoldable> + Lift> + Copy +{ fn type_op_method( tcx: TyCtxt<'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize>>, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 4fa2455c42de1..69d11b45e6045 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -11,6 +11,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::HigherRankedType; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; +use rustc_infer::traits::ObligationCauseCode; use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData}; use rustc_middle::ty::{ self, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, ToPredicate, @@ -25,10 +26,9 @@ use crate::traits::vtable::{ VtblSegment, }; use crate::traits::{ - BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource, - ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause, PolyTraitObligation, - PredicateObligation, Selection, SelectionError, SignatureMismatch, TraitNotObjectSafe, - TraitObligation, Unimplemented, + ImplDerivedCause, ImplSource, ImplSourceUserDefinedData, Normalized, Obligation, + ObligationCause, PolyTraitObligation, PredicateObligation, Selection, SelectionError, + SignatureMismatch, TraitNotObjectSafe, TraitObligation, Unimplemented, }; use super::BuiltinImplConditions; @@ -275,7 +275,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { bug!("obligation {:?} had matched a builtin impl but now doesn't", obligation); }; - let cause = obligation.derived_cause(BuiltinDerivedObligation); + let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); self.collect_predicates_for_types( obligation.param_env, cause, @@ -435,7 +435,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Vec> { debug!(?nested, "vtable_auto_impl"); ensure_sufficient_stack(|| { - let cause = obligation.derived_cause(BuiltinDerivedObligation); + let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); let trait_ref = self.infcx.enter_forall_and_leak_universe(poly_trait_ref); @@ -606,7 +606,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { for assoc_type in assoc_types { let defs: &ty::Generics = tcx.generics_of(assoc_type); - if !defs.params.is_empty() && !tcx.features().generic_associated_types_extended { + if !defs.own_params.is_empty() && !tcx.features().generic_associated_types_extended { tcx.dcx().span_delayed_bug( obligation.cause.span, "GATs in trait object shouldn't have been considered", @@ -693,7 +693,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let vtable_base = vtable_trait_first_method_offset( tcx, - (unnormalized_upcast_trait_ref, ty::Binder::dummy(object_trait_ref)), + unnormalized_upcast_trait_ref, + ty::Binder::dummy(object_trait_ref), ); Ok(ImplSource::Builtin(BuiltinImplSource::Object { vtable_base: vtable_base }, nested)) @@ -722,7 +723,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut nested = self.equate_trait_refs(obligation.with(tcx, placeholder_predicate), trait_ref)?; - let cause = obligation.derived_cause(BuiltinDerivedObligation); + let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); // Confirm the `type Output: Sized;` bound that is present on `FnOnce` let output_ty = self.infcx.enter_forall_and_leak_universe(sig.output()); @@ -734,7 +735,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { output_ty, &mut nested, ); - let tr = ty::TraitRef::from_lang_item(self.tcx(), LangItem::Sized, cause.span, [output_ty]); + let tr = ty::TraitRef::new( + self.tcx(), + self.tcx().require_lang_item(LangItem::Sized, Some(cause.span)), + [output_ty], + ); nested.push(Obligation::new(self.infcx.tcx, cause, obligation.param_env, tr)); Ok(nested) @@ -1008,10 +1013,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else { nested.push(obligation.with( self.tcx(), - ty::TraitRef::from_lang_item( + ty::TraitRef::new( self.tcx(), - LangItem::AsyncFnKindHelper, - obligation.cause.span, + self.tcx().require_lang_item( + LangItem::AsyncFnKindHelper, + Some(obligation.cause.span), + ), [kind_ty, Ty::from_closure_kind(self.tcx(), goal_kind)], ), )); @@ -1240,10 +1247,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .collect(); // We can only make objects from sized types. - let tr = ty::TraitRef::from_lang_item( + let tr = ty::TraitRef::new( tcx, - LangItem::Sized, - obligation.cause.span, + tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span)), [source], ); nested.push(predicate_to_obligation(tr.to_predicate(tcx))); @@ -1380,7 +1386,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = obligation.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty)); let mut nested = vec![]; - let cause = obligation.derived_cause(BuiltinDerivedObligation); + let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); // If we have a custom `impl const Drop`, then // first check it like a regular impl candidate. @@ -1395,7 +1401,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?args, "impl args"); let cause = obligation.derived_cause(|derived| { - ImplDerivedObligation(Box::new(ImplDerivedObligationCause { + ObligationCauseCode::ImplDerived(Box::new(ImplDerivedCause { derived, impl_or_alias_def_id: impl_def_id, impl_def_predicate_index: None, @@ -1473,10 +1479,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { cause.clone(), obligation.recursion_depth + 1, self_ty.rebind(ty::TraitPredicate { - trait_ref: ty::TraitRef::from_lang_item( + trait_ref: ty::TraitRef::new( self.tcx(), - LangItem::Destruct, - cause.span, + self.tcx().require_lang_item(LangItem::Destruct, Some(cause.span)), [nested_ty.into(), host_effect_param], ), polarity: ty::PredicatePolarity::Positive, @@ -1506,10 +1511,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Infer(_) | ty::Placeholder(_) => { let predicate = self_ty.rebind(ty::TraitPredicate { - trait_ref: ty::TraitRef::from_lang_item( + trait_ref: ty::TraitRef::new( self.tcx(), - LangItem::Destruct, - cause.span, + self.tcx().require_lang_item(LangItem::Destruct, Some(cause.span)), [nested_ty.into(), host_effect_param], ), polarity: ty::PredicatePolarity::Positive, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 18cb3184fe114..7aa2aabed7f72 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -13,9 +13,9 @@ use super::util; use super::util::closure_trait_ref_and_return_type; use super::wf; use super::{ - ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation, ObligationCause, - ObligationCauseCode, Overflow, PolyTraitObligation, PredicateObligation, Selection, - SelectionError, SelectionResult, TraitQueryMode, + ImplDerivedCause, Normalized, Obligation, ObligationCause, ObligationCauseCode, Overflow, + PolyTraitObligation, PredicateObligation, Selection, SelectionError, SelectionResult, + TraitQueryMode, }; use crate::infer::{InferCtxt, InferOk, TypeFreshener}; @@ -41,6 +41,7 @@ use rustc_middle::dep_graph::DepNodeIndex; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::_match::MatchAgainstFreshVars; use rustc_middle::ty::abstract_const::NotConstEvaluatable; +use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, PolyProjectionPredicate, ToPredicate}; @@ -1777,7 +1778,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If this type is a GAT, and of the GAT args resolve to something new, // that means that we must have newly inferred something about the GAT. // We should give up in that case. - if !generics.params.is_empty() + if !generics.own_params.is_empty() && obligation.predicate.args[generics.parent_count..].iter().any(|&p| { p.has_non_region_infer() && self.infcx.resolve_vars_if_possible(p) != p }) @@ -2441,7 +2442,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { }); let tcx = self.tcx(); - let trait_ref = if tcx.generics_of(trait_def_id).params.len() == 1 { + let trait_ref = if tcx.generics_of(trait_def_id).own_params.len() == 1 { ty::TraitRef::new(tcx, trait_def_id, [normalized_ty]) } else { // If this is an ill-formed auto/built-in trait, then synthesize @@ -2771,7 +2772,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { cause.clone() } else { cause.clone().derived_cause(parent_trait_pred, |derived| { - ImplDerivedObligation(Box::new(ImplDerivedObligationCause { + ObligationCauseCode::ImplDerived(Box::new(ImplDerivedCause { derived, impl_or_alias_def_id: def_id, impl_def_predicate_index: Some(index), diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 390e711a18d95..fe3f66f3a3ff2 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -11,6 +11,7 @@ pub mod specialization_graph; use rustc_infer::infer::DefineOpaqueTypes; +use rustc_middle::ty::print::PrintTraitRefExt as _; use specialization_graph::GraphExt; use crate::errors::NegativePositiveConflict; diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index 64ab8378abb00..96a06e0c16918 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -1,5 +1,4 @@ use rustc_infer::infer::at::At; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::traits::{FulfillmentError, TraitEngine}; use rustc_macros::extension; use rustc_middle::ty::{self, Ty}; @@ -20,9 +19,7 @@ impl<'tcx> At<'_, 'tcx> { return Ok(ty); }; - let new_infer_ty = self - .infcx - .next_ty_var(TypeVariableOrigin { param_def_id: None, span: self.cause.span }); + let new_infer_ty = self.infcx.next_ty_var(self.cause.span); // We simply emit an `alias-eq` goal here, since that will take care of // normalizing the LHS of the projection until it is a rigid projection diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 178f3c63ef73c..3f1ba80acd3d9 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -320,16 +320,11 @@ fn vtable_entries<'tcx>( } /// Find slot base for trait methods within vtable entries of another trait -// FIXME(@lcnr): This isn't a query, so why does it take a tuple as its argument. pub(super) fn vtable_trait_first_method_offset<'tcx>( tcx: TyCtxt<'tcx>, - key: ( - ty::PolyTraitRef<'tcx>, // trait_to_be_found - ty::PolyTraitRef<'tcx>, // trait_owning_vtable - ), + trait_to_be_found: ty::PolyTraitRef<'tcx>, + trait_owning_vtable: ty::PolyTraitRef<'tcx>, ) -> usize { - let (trait_to_be_found, trait_owning_vtable) = key; - // #90177 let trait_to_be_found_erased = tcx.erase_regions(trait_to_be_found); diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 28ee76f7145c2..562a82cc73d65 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -2,6 +2,7 @@ use crate::infer::InferCtxt; use crate::traits; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; +use rustc_infer::traits::ObligationCauseCode; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; @@ -333,7 +334,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { return self.out; } - let cause = self.cause(traits::WellFormed(None)); + let cause = self.cause(ObligationCauseCode::WellFormed(None)); let param_env = self.param_env; let mut obligations = Vec::with_capacity(self.out.len()); for mut obligation in self.out { @@ -381,7 +382,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { if let Some(parent_trait_pred) = predicate.to_opt_poly_trait_pred() { cause = cause.derived_cause( parent_trait_pred, - traits::ObligationCauseCode::WellFormedDerivedObligation, + traits::ObligationCauseCode::WellFormedDerived, ); } extend_cause_with_original_assoc_item_obligation(tcx, item, &mut cause, predicate); @@ -485,7 +486,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { &mut traits::SelectionContext::new(self.infcx), self.param_env, data, - self.cause(traits::WellFormed(None)), + self.cause(ObligationCauseCode::WellFormed(None)), self.recursion_depth, &mut self.out, ); @@ -498,7 +499,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { fn compute_projection_args(&mut self, args: GenericArgsRef<'tcx>) { let tcx = self.tcx(); - let cause = self.cause(traits::WellFormed(None)); + let cause = self.cause(ObligationCauseCode::WellFormed(None)); let param_env = self.param_env; let depth = self.recursion_depth; @@ -525,8 +526,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { if !subty.has_escaping_bound_vars() { let cause = self.cause(cause); - let trait_ref = - ty::TraitRef::from_lang_item(self.tcx(), LangItem::Sized, cause.span, [subty]); + let trait_ref = ty::TraitRef::new( + self.tcx(), + self.tcx().require_lang_item(LangItem::Sized, Some(cause.span)), + [subty], + ); self.out.push(traits::Obligation::with_depth( self.tcx(), cause, @@ -564,11 +568,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { iter::zip(predicates, origins.into_iter().rev()) .map(|((pred, span), origin_def_id)| { - let code = if span.is_dummy() { - traits::ItemObligation(origin_def_id) - } else { - traits::BindingObligation(origin_def_id, span) - }; + let code = ObligationCauseCode::WhereClause(origin_def_id, span); let cause = self.cause(code); traits::Obligation::with_depth( self.tcx(), @@ -626,7 +626,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.reserve(implicit_bounds.len()); for implicit_bound in implicit_bounds { - let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound)); + let cause = self.cause(ObligationCauseCode::ObjectTypeBound(ty, explicit_bound)); let outlives = ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound)); self.out.push(traits::Obligation::with_depth( @@ -644,7 +644,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { type Result = (); - fn visit_ty(&mut self, t: as ty::Interner>::Ty) -> Self::Result { + fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { debug!("wf bounds for t={:?} t.kind={:#?}", t, t.kind()); let tcx = self.tcx(); @@ -673,22 +673,22 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { ty::Infer(ty::FloatVar(_)) => {} ty::Slice(subty) => { - self.require_sized(subty, traits::SliceOrArrayElem); + self.require_sized(subty, ObligationCauseCode::SliceOrArrayElem); } ty::Array(subty, _) => { - self.require_sized(subty, traits::SliceOrArrayElem); + self.require_sized(subty, ObligationCauseCode::SliceOrArrayElem); // Note that we handle the len is implicitly checked while walking `arg`. } ty::Pat(subty, _) => { - self.require_sized(subty, traits::MiscObligation); + self.require_sized(subty, ObligationCauseCode::Misc); } ty::Tuple(tys) => { if let Some((_last, rest)) = tys.split_last() { for &elem in rest { - self.require_sized(elem, traits::TupleElem); + self.require_sized(elem, ObligationCauseCode::TupleElem); } } } @@ -728,7 +728,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { ty::Ref(r, rty, _) => { // WfReference if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() { - let cause = self.cause(traits::ReferenceOutlivesReferent(t)); + let cause = self.cause(ObligationCauseCode::ReferenceOutlivesReferent(t)); self.out.push(traits::Obligation::with_depth( tcx, cause, @@ -825,7 +825,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { if let Some(principal) = data.principal_def_id() { self.out.push(traits::Obligation::with_depth( tcx, - self.cause(traits::WellFormed(None)), + self.cause(ObligationCauseCode::WellFormed(None)), self.recursion_depth, self.param_env, ty::Binder::dummy(ty::PredicateKind::ObjectSafe(principal)), @@ -847,7 +847,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { // See also the comment on `fn obligations`, describing "livelock" // prevention, which happens before this can be reached. ty::Infer(_) => { - let cause = self.cause(traits::WellFormed(None)); + let cause = self.cause(ObligationCauseCode::WellFormed(None)); self.out.push(traits::Obligation::with_depth( tcx, cause, @@ -863,7 +863,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { t.super_visit_with(self) } - fn visit_const(&mut self, c: as ty::Interner>::Const) -> Self::Result { + fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result { let tcx = self.tcx(); match c.kind() { @@ -875,7 +875,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( ty::ClauseKind::ConstEvaluatable(c), )); - let cause = self.cause(traits::WellFormed(None)); + let cause = self.cause(ObligationCauseCode::WellFormed(None)); self.out.push(traits::Obligation::with_depth( tcx, cause, @@ -886,7 +886,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { } } ty::ConstKind::Infer(_) => { - let cause = self.cause(traits::WellFormed(None)); + let cause = self.cause(ObligationCauseCode::WellFormed(None)); self.out.push(traits::Obligation::with_depth( tcx, @@ -909,7 +909,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( ty::ClauseKind::ConstEvaluatable(c), )); - let cause = self.cause(traits::WellFormed(None)); + let cause = self.cause(ObligationCauseCode::WellFormed(None)); self.out.push(traits::Obligation::with_depth( tcx, cause, @@ -933,7 +933,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { c.super_visit_with(self) } - fn visit_predicate(&mut self, _p: as ty::Interner>::Predicate) -> Self::Result { + fn visit_predicate(&mut self, _p: ty::Predicate<'tcx>) -> Self::Result { bug!("predicate should not be checked for well-formedness"); } } diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index 01b9a5640b86a..b6a59a4ad3a4c 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -3,7 +3,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::{Clause, ParamEnvAnd}; -use rustc_middle::ty::{FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{FnSig, PolyFnSig, Ty, TyCtxt, TypeFoldable}; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::query::type_op::ascribe_user_type::{ @@ -54,7 +54,7 @@ fn type_op_normalize<'tcx, T>( key: ParamEnvAnd<'tcx, Normalize>, ) -> Result where - T: fmt::Debug + TypeFoldable> + Lift<'tcx>, + T: fmt::Debug + TypeFoldable>, { let (param_env, Normalize { value }) = key.into_parts(); let Normalized { value, obligations } = diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index ba75424ec0c6d..d3fe8291e03c3 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -340,22 +340,22 @@ fn associated_type_for_impl_trait_in_impl( impl_assoc_ty.generics_of({ let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id); let trait_assoc_parent_count = trait_assoc_generics.parent_count; - let mut params = trait_assoc_generics.params.clone(); + let mut own_params = trait_assoc_generics.own_params.clone(); let parent_generics = tcx.generics_of(impl_local_def_id.to_def_id()); - let parent_count = parent_generics.parent_count + parent_generics.params.len(); + let parent_count = parent_generics.parent_count + parent_generics.own_params.len(); - for param in &mut params { + for param in &mut own_params { param.index = param.index + parent_count as u32 - trait_assoc_parent_count as u32; } let param_def_id_to_index = - params.iter().map(|param| (param.def_id, param.index)).collect(); + own_params.iter().map(|param| (param.def_id, param.index)).collect(); ty::Generics { parent: Some(impl_local_def_id.to_def_id()), parent_count, - params, + own_params, param_def_id_to_index, has_self: false, has_late_bound_regions: trait_assoc_generics.has_late_bound_regions, diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index e1534af4987df..862fb2e166394 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -69,7 +69,8 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' // case, since it has been liberated), map it back to the early-bound lifetime of // the GAT. Since RPITITs also have all of the fn's generics, we slice only // the end of the list corresponding to the opaque's generics. - for param in &generics.params[tcx.generics_of(fn_def_id).params.len()..] { + for param in &generics.own_params[tcx.generics_of(fn_def_id).own_params.len()..] + { let orig_lt = tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()); if matches!(*orig_lt, ty::ReLateParam(..)) { diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 902b76e8c1e26..f78a28d16fdf5 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -5,7 +5,7 @@ use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::{CoroutineLayout, CoroutineSavedLocal}; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{ - IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES, + FloatExt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES, }; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ @@ -180,12 +180,7 @@ fn layout_of_uncached<'tcx>( )), ty::Int(ity) => scalar(Int(Integer::from_int_ty(dl, ity), true)), ty::Uint(ity) => scalar(Int(Integer::from_uint_ty(dl, ity), false)), - ty::Float(fty) => scalar(match fty { - ty::FloatTy::F16 => F16, - ty::FloatTy::F32 => F32, - ty::FloatTy::F64 => F64, - ty::FloatTy::F128 => F128, - }), + ty::Float(fty) => scalar(Float(Float::from_float_ty(fty))), ty::FnPtr(_) => { let mut ptr = scalar_unit(Pointer(dl.instruction_address_space)); ptr.valid_range_mut().start = 1; diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index a5ffa553c2a8a..446f16b412546 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -85,7 +85,7 @@ fn representability_adt_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Representab fn params_in_repr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> BitSet { let adt_def = tcx.adt_def(def_id); let generics = tcx.generics_of(def_id); - let mut params_in_repr = BitSet::new_empty(generics.params.len()); + let mut params_in_repr = BitSet::new_empty(generics.own_params.len()); for variant in adt_def.variants() { for field in variant.fields.iter() { params_in_repr_ty( diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 79ff60802d28e..cef3f4e8ce05f 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -13,7 +13,8 @@ rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_span = { path = "../rustc_span", optional = true } -smallvec = { version = "1.8.1" } +rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } +smallvec = { version = "1.8.1", default-features = false } # tidy-alphabetical-end [features] diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs deleted file mode 100644 index 57f961ac97ec5..0000000000000 --- a/compiler/rustc_type_ir/src/binder.rs +++ /dev/null @@ -1,7 +0,0 @@ -use crate::Interner; - -pub trait BoundVars { - fn bound_vars(&self) -> I::BoundVars; - - fn has_no_bound_vars(&self) -> bool; -} diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index f041c5831fc7a..efefd174cd6f0 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -1,19 +1,25 @@ -use rustc_ast_ir::try_visit; -use rustc_ast_ir::visit::VisitorResult; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use std::fmt; use std::hash::Hash; -use crate::fold::{FallibleTypeFolder, TypeFoldable}; -use crate::visit::{TypeVisitable, TypeVisitor}; -use crate::{Interner, PlaceholderLike, UniverseIndex}; +use crate::inherent::*; +use crate::{Interner, UniverseIndex}; /// A "canonicalized" type `V` is one where all free inference /// variables have been rewritten to "canonical vars". These are /// numbered starting from 0 in order of first appearance. #[derive(derivative::Derivative)] -#[derivative(Clone(bound = "V: Clone"), Hash(bound = "V: Hash"))] +#[derivative( + Clone(bound = "V: Clone"), + Hash(bound = "V: Hash"), + PartialEq(bound = "V: PartialEq"), + Eq(bound = "V: Eq"), + Debug(bound = "V: fmt::Debug"), + Copy(bound = "V: Copy") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub struct Canonical { pub value: V, @@ -63,18 +69,6 @@ impl Canonical { } } -impl Eq for Canonical {} - -impl PartialEq for Canonical { - fn eq(&self, other: &Self) -> bool { - 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 fmt::Display for Canonical { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Self { value, max_universe, variables, defining_opaque_types } = self; @@ -85,84 +79,25 @@ impl fmt::Display for Canonical { } } -impl fmt::Debug for Canonical { - 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", &value) - .field("max_universe", &max_universe) - .field("variables", &variables) - .field("defining_opaque_types", &defining_opaque_types) - .finish() - } -} - -impl Copy for Canonical where I::CanonicalVars: Copy {} - -impl> TypeFoldable for Canonical -where - I::CanonicalVars: TypeFoldable, -{ - fn try_fold_with>(self, folder: &mut F) -> Result { - Ok(Canonical { - 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, - }) - } -} - -impl> TypeVisitable for Canonical -where - I::CanonicalVars: TypeVisitable, -{ - fn visit_with>(&self, folder: &mut F) -> F::Result { - 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) - } -} - /// Information about a canonical variable that is included with the /// canonical value. This is sufficient information for code to create /// a copy of the canonical value in some other inference context, /// with fresh inference variables replacing the canonical values. #[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Debug(bound = ""))] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + Debug(bound = ""), + Eq(bound = ""), + PartialEq(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub struct CanonicalVarInfo { pub kind: CanonicalVarKind, } -impl PartialEq for CanonicalVarInfo { - fn eq(&self, other: &Self) -> bool { - self.kind == other.kind - } -} - -impl Eq for CanonicalVarInfo {} - -impl TypeVisitable for CanonicalVarInfo -where - I::Ty: TypeVisitable, -{ - fn visit_with>(&self, visitor: &mut V) -> V::Result { - self.kind.visit_with(visitor) - } -} - -impl TypeFoldable for CanonicalVarInfo -where - I::Ty: TypeFoldable, -{ - fn try_fold_with>(self, folder: &mut F) -> Result { - Ok(CanonicalVarInfo { kind: self.kind.try_fold_with(folder)? }) - } -} - impl CanonicalVarInfo { pub fn universe(self) -> UniverseIndex { self.kind.universe() @@ -215,6 +150,7 @@ impl CanonicalVarInfo { /// that analyzes type-like values. #[derive(derivative::Derivative)] #[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Debug(bound = ""))] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub enum CanonicalVarKind { /// Some kind of type inference variable. @@ -257,51 +193,6 @@ impl PartialEq for CanonicalVarKind { } } -impl Eq for CanonicalVarKind {} - -impl TypeVisitable for CanonicalVarKind -where - I::Ty: TypeVisitable, -{ - fn visit_with>(&self, visitor: &mut V) -> V::Result { - match self { - CanonicalVarKind::Ty(_) - | CanonicalVarKind::PlaceholderTy(_) - | CanonicalVarKind::Region(_) - | CanonicalVarKind::PlaceholderRegion(_) - | CanonicalVarKind::Effect => V::Result::output(), - CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => { - ty.visit_with(visitor) - } - } - } -} - -impl TypeFoldable for CanonicalVarKind -where - I::Ty: TypeFoldable, -{ - fn try_fold_with>(self, folder: &mut F) -> Result { - Ok(match self { - CanonicalVarKind::Ty(kind) => CanonicalVarKind::Ty(kind), - CanonicalVarKind::Region(kind) => CanonicalVarKind::Region(kind), - CanonicalVarKind::Const(kind, ty) => { - CanonicalVarKind::Const(kind, ty.try_fold_with(folder)?) - } - CanonicalVarKind::PlaceholderTy(placeholder) => { - CanonicalVarKind::PlaceholderTy(placeholder) - } - CanonicalVarKind::PlaceholderRegion(placeholder) => { - CanonicalVarKind::PlaceholderRegion(placeholder) - } - CanonicalVarKind::PlaceholderConst(placeholder, ty) => { - CanonicalVarKind::PlaceholderConst(placeholder, ty.try_fold_with(folder)?) - } - CanonicalVarKind::Effect => CanonicalVarKind::Effect, - }) - } -} - impl CanonicalVarKind { pub fn universe(self) -> UniverseIndex { match self { @@ -354,6 +245,7 @@ impl CanonicalVarKind { /// usize or f32). In order to faithfully reproduce a type, we need to /// know what set of types a given type variable can be unified with. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] pub enum CanonicalTyVarKind { /// General type variable `?T` that can be unified with arbitrary types. diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index c1506f9252b08..c748cdf6ed278 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -10,7 +10,7 @@ use self::ConstKind::*; /// Represents a constant in Rust. #[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""))] +#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum ConstKind { /// A const generic parameter. @@ -58,8 +58,6 @@ impl PartialEq for ConstKind { } } -impl Eq for ConstKind {} - impl fmt::Debug for ConstKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { WithInfcx::with_no_infcx(self).fmt(f) diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs new file mode 100644 index 0000000000000..a50967a3b182a --- /dev/null +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -0,0 +1,110 @@ +use std::fmt::Debug; +use std::hash::Hash; +use std::ops::Deref; + +use crate::fold::TypeSuperFoldable; +use crate::visit::{Flags, TypeSuperVisitable}; +use crate::{ + BoundVar, ConstKind, DebruijnIndex, DebugWithInfcx, Interner, RegionKind, TyKind, UniverseIndex, +}; + +pub trait Ty>: + Copy + + DebugWithInfcx + + Hash + + Eq + + Into + + IntoKind> + + TypeSuperVisitable + + TypeSuperFoldable + + Flags +{ + fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self; +} + +pub trait Region>: + Copy + DebugWithInfcx + Hash + Eq + Into + IntoKind> + Flags +{ + fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self; + + fn new_static(interner: I) -> Self; +} + +pub trait Const>: + Copy + + DebugWithInfcx + + Hash + + Eq + + Into + + IntoKind> + + TypeSuperVisitable + + TypeSuperFoldable + + Flags +{ + fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar, ty: I::Ty) -> Self; + + fn ty(self) -> I::Ty; +} + +pub trait GenericsOf> { + fn count(&self) -> usize; +} + +pub trait GenericArgs>: + Copy + + DebugWithInfcx + + Hash + + Eq + + IntoIterator + + Deref> +{ + fn type_at(self, i: usize) -> I::Ty; + + fn identity_for_item(interner: I, def_id: I::DefId) -> I::GenericArgs; +} + +pub trait Predicate>: + Copy + Debug + Hash + Eq + TypeSuperVisitable + TypeSuperFoldable + Flags +{ +} + +/// Common capabilities of placeholder kinds +pub trait PlaceholderLike: Copy + Debug + Hash + Eq { + fn universe(self) -> UniverseIndex; + fn var(self) -> BoundVar; + + fn with_updated_universe(self, ui: UniverseIndex) -> Self; + + fn new(ui: UniverseIndex, var: BoundVar) -> Self; +} + +pub trait IntoKind { + type Kind; + + fn kind(self) -> Self::Kind; +} + +pub trait BoundVars { + fn bound_vars(&self) -> I::BoundVars; + + fn has_no_bound_vars(&self) -> bool; +} + +// FIXME: Uplift `AliasTy` +pub trait AliasTy: Copy + DebugWithInfcx + Hash + Eq + Sized { + fn new( + interner: I, + trait_def_id: I::DefId, + args: impl IntoIterator>, + ) -> Self; + + fn def_id(self) -> I::DefId; + + fn args(self) -> I::GenericArgs; + + fn trait_def_id(self, interner: I) -> I::DefId; + + fn self_ty(self) -> I::Ty; + + fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self; +} diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 70f7e58be1937..17d9f4242fdfa 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -2,23 +2,31 @@ use smallvec::SmallVec; use std::fmt::Debug; use std::hash::Hash; -use crate::fold::TypeSuperFoldable; +use crate::inherent::*; +use crate::ir_print::IrPrint; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{ - new, BoundVar, BoundVars, CanonicalVarInfo, ConstKind, DebugWithInfcx, RegionKind, TyKind, - UniverseIndex, + CanonicalVarInfo, CoercePredicate, DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, + NormalizesTo, ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, }; -pub trait Interner: Sized + Copy { +pub trait Interner: + Sized + + Copy + + IrPrint> + + IrPrint> + + IrPrint> + + IrPrint> + + IrPrint> + + IrPrint> + + IrPrint> + + IrPrint> +{ type DefId: Copy + Debug + Hash + Eq; type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable; type AdtDef: Copy + Debug + Hash + Eq; - type GenericArgs: Copy - + DebugWithInfcx - + Hash - + Eq - + IntoIterator; + type GenericArgs: GenericArgs; type GenericArg: Copy + DebugWithInfcx + Hash + Eq; type Term: Copy + Debug + Hash + Eq; @@ -29,21 +37,12 @@ pub trait Interner: Sized + Copy { type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator>; // Kinds of tys - type Ty: Copy - + DebugWithInfcx - + Hash - + Eq - + Into - + IntoKind> - + TypeSuperVisitable - + TypeSuperFoldable - + Flags - + new::Ty; + type Ty: Ty; type Tys: Copy + Debug + Hash + Eq + IntoIterator; - type AliasTy: Copy + DebugWithInfcx + Hash + Eq; + type AliasTy: AliasTy; type ParamTy: Copy + Debug + Hash + Eq; type BoundTy: Copy + Debug + Hash + Eq; - type PlaceholderTy: Copy + Debug + Hash + Eq + PlaceholderLike; + type PlaceholderTy: PlaceholderLike; // Things stored inside of tys type ErrorGuaranteed: Copy + Debug + Hash + Eq; @@ -53,47 +52,24 @@ pub trait Interner: Sized + Copy { type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx; // Kinds of consts - type Const: Copy - + DebugWithInfcx - + Hash - + Eq - + Into - + IntoKind> - + ConstTy - + TypeSuperVisitable - + TypeSuperFoldable - + Flags - + new::Const; + type Const: Const; type AliasConst: Copy + DebugWithInfcx + Hash + Eq; - type PlaceholderConst: Copy + Debug + Hash + Eq + PlaceholderLike; + type PlaceholderConst: PlaceholderLike; type ParamConst: Copy + Debug + Hash + Eq; type BoundConst: Copy + Debug + Hash + Eq; type ValueConst: Copy + Debug + Hash + Eq; type ExprConst: Copy + DebugWithInfcx + Hash + Eq; // Kinds of regions - type Region: Copy - + DebugWithInfcx - + Hash - + Eq - + Into - + IntoKind> - + Flags - + new::Region; + type Region: Region; type EarlyParamRegion: Copy + Debug + Hash + Eq; type LateParamRegion: Copy + Debug + Hash + Eq; type BoundRegion: Copy + Debug + Hash + Eq; type InferRegion: Copy + DebugWithInfcx + Hash + Eq; - type PlaceholderRegion: Copy + Debug + Hash + Eq + PlaceholderLike; + type PlaceholderRegion: PlaceholderLike; // Predicates - type Predicate: Copy - + Debug - + Hash - + Eq - + TypeSuperVisitable - + TypeSuperFoldable - + Flags; + type Predicate: Predicate; type TraitPredicate: Copy + Debug + Hash + Eq; type RegionOutlivesPredicate: Copy + Debug + Hash + Eq; type TypeOutlivesPredicate: Copy + Debug + Hash + Eq; @@ -105,26 +81,19 @@ pub trait Interner: Sized + Copy { type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable + Flags; fn mk_canonical_var_infos(self, infos: &[CanonicalVarInfo]) -> Self::CanonicalVars; -} - -/// Common capabilities of placeholder kinds -pub trait PlaceholderLike { - fn universe(self) -> UniverseIndex; - fn var(self) -> BoundVar; - fn with_updated_universe(self, ui: UniverseIndex) -> Self; + type GenericsOf: GenericsOf; + fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf; - fn new(ui: UniverseIndex, var: BoundVar) -> Self; -} + fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs; -pub trait IntoKind { - type Kind; - - fn kind(self) -> Self::Kind; -} + fn check_and_mk_args( + self, + def_id: Self::DefId, + args: impl IntoIterator>, + ) -> Self::GenericArgs; -pub trait ConstTy { - fn ty(self) -> I::Ty; + fn parent(self, def_id: Self::DefId) -> Self::DefId; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs new file mode 100644 index 0000000000000..5885139754afe --- /dev/null +++ b/compiler/rustc_type_ir/src/ir_print.rs @@ -0,0 +1,48 @@ +use std::fmt; + +use crate::{ + CoercePredicate, ExistentialProjection, ExistentialTraitRef, Interner, NormalizesTo, + ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef, +}; + +pub trait IrPrint { + fn print(t: &T, fmt: &mut fmt::Formatter<'_>) -> fmt::Result; + fn print_debug(t: &T, fmt: &mut fmt::Formatter<'_>) -> fmt::Result; +} + +macro_rules! define_display_via_print { + ($($ty:ident),+ $(,)?) => { + $( + impl fmt::Display for $ty { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + >>::print(self, fmt) + } + } + )* + } +} + +macro_rules! define_debug_via_print { + ($($ty:ident),+ $(,)?) => { + $( + impl fmt::Debug for $ty { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + >>::print_debug(self, fmt) + } + } + )* + } +} + +define_display_via_print!( + TraitRef, + TraitPredicate, + ExistentialTraitRef, + ExistentialProjection, + ProjectionPredicate, + NormalizesTo, + SubtypePredicate, + CoercePredicate, +); + +define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection); diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index ef7437c2542cf..04cacd987d098 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -23,23 +23,24 @@ pub mod visit; #[cfg(feature = "nightly")] pub mod codec; pub mod fold; -pub mod new; +pub mod inherent; +pub mod ir_print; +pub mod lift; pub mod ty_info; pub mod ty_kind; #[macro_use] mod macros; -mod binder; mod canonical; mod const_kind; mod debug; mod flags; mod infcx; mod interner; +mod predicate; mod predicate_kind; mod region_kind; -pub use binder::*; pub use canonical::*; #[cfg(feature = "nightly")] pub use codec::*; @@ -48,6 +49,7 @@ pub use debug::{DebugWithInfcx, WithInfcx}; pub use flags::*; pub use infcx::InferCtxtLike; pub use interner::*; +pub use predicate::*; pub use predicate_kind::*; pub use region_kind::*; pub use ty_info::*; diff --git a/compiler/rustc_type_ir/src/lift.rs b/compiler/rustc_type_ir/src/lift.rs new file mode 100644 index 0000000000000..839da10db5e56 --- /dev/null +++ b/compiler/rustc_type_ir/src/lift.rs @@ -0,0 +1,21 @@ +/// A trait implemented for all `X<'a>` types that can be safely and +/// efficiently converted to `X<'tcx>` as long as they are part of the +/// provided `TyCtxt<'tcx>`. +/// This can be done, for example, for `Ty<'tcx>` or `GenericArgsRef<'tcx>` +/// by looking them up in their respective interners. +/// +/// However, this is still not the best implementation as it does +/// need to compare the components, even for interned values. +/// It would be more efficient if `TypedArena` provided a way to +/// determine whether the address is in the allocated range. +/// +/// `None` is returned if the value or one of the components is not part +/// of the provided context. +/// For `Ty`, `None` can be returned if either the type interner doesn't +/// contain the `TyKind` key or if the address of the interned +/// pointer differs. The latter case is possible if a primitive type, +/// e.g., `()` or `u8`, was interned in a different context. +pub trait Lift: std::fmt::Debug { + type Lifted: std::fmt::Debug; + fn lift_to_tcx(self, tcx: I) -> Option; +} diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index 7dcc8851a43f2..f2f7b165de52f 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -53,4 +53,5 @@ TrivialTypeTraversalImpls! { crate::UniverseIndex, rustc_ast_ir::Mutability, rustc_ast_ir::Movability, + crate::PredicatePolarity, } diff --git a/compiler/rustc_type_ir/src/new.rs b/compiler/rustc_type_ir/src/new.rs deleted file mode 100644 index 1572a641d06f0..0000000000000 --- a/compiler/rustc_type_ir/src/new.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::{BoundVar, DebruijnIndex, Interner}; - -pub trait Ty> { - fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self; -} - -pub trait Region> { - fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self; - - fn new_static(interner: I) -> Self; -} - -pub trait Const> { - fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar, ty: I::Ty) -> Self; -} diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs new file mode 100644 index 0000000000000..f84f8f47c6767 --- /dev/null +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -0,0 +1,434 @@ +use std::fmt; + +use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; + +use crate::inherent::*; +use crate::visit::TypeVisitableExt as _; +use crate::{DebugWithInfcx, Interner}; + +/// A complete reference to a trait. These take numerous guises in syntax, +/// but perhaps the most recognizable form is in a where-clause: +/// ```ignore (illustrative) +/// T: Foo +/// ``` +/// This would be represented by a trait-reference where the `DefId` is the +/// `DefId` for the trait `Foo` and the args define `T` as parameter 0, +/// and `U` as parameter 1. +/// +/// Trait references also appear in object types like `Foo`, but in +/// that case the `Self` parameter is absent from the generic parameters. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct TraitRef { + pub def_id: I::DefId, + pub args: I::GenericArgs, + /// This field exists to prevent the creation of `TraitRef` without + /// calling [`TraitRef::new`]. + _use_trait_ref_new_instead: (), +} + +impl TraitRef { + pub fn new( + interner: I, + trait_def_id: I::DefId, + args: impl IntoIterator>, + ) -> Self { + let args = interner.check_and_mk_args(trait_def_id, args); + Self { def_id: trait_def_id, args, _use_trait_ref_new_instead: () } + } + + pub fn from_method(interner: I, trait_id: I::DefId, args: I::GenericArgs) -> TraitRef { + let generics = interner.generics_of(trait_id); + TraitRef::new(interner, trait_id, args.into_iter().take(generics.count())) + } + + /// Returns a `TraitRef` of the form `P0: Foo` where `Pi` + /// are the parameters defined on trait. + pub fn identity(interner: I, def_id: I::DefId) -> TraitRef { + TraitRef::new(interner, def_id, I::GenericArgs::identity_for_item(interner, def_id)) + } + + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + TraitRef::new( + interner, + self.def_id, + [self_ty.into()].into_iter().chain(self.args.into_iter().skip(1)), + ) + } + + #[inline] + pub fn self_ty(&self) -> I::Ty { + self.args.type_at(0) + } +} + +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct TraitPredicate { + pub trait_ref: TraitRef, + + /// If polarity is Positive: we are proving that the trait is implemented. + /// + /// If polarity is Negative: we are proving that a negative impl of this trait + /// exists. (Note that coherence also checks whether negative impls of supertraits + /// exist via a series of predicates.) + /// + /// If polarity is Reserved: that's a bug. + pub polarity: PredicatePolarity, +} + +impl TraitPredicate { + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self { + Self { trait_ref: self.trait_ref.with_self_ty(interner, self_ty), polarity: self.polarity } + } + + pub fn def_id(self) -> I::DefId { + self.trait_ref.def_id + } + + pub fn self_ty(self) -> I::Ty { + self.trait_ref.self_ty() + } +} + +impl fmt::Debug for TraitPredicate { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // FIXME(effects) printing? + write!(f, "TraitPredicate({:?}, polarity:{:?})", self.trait_ref, self.polarity) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub enum ImplPolarity { + /// `impl Trait for Type` + Positive, + /// `impl !Trait for Type` + Negative, + /// `#[rustc_reservation_impl] impl Trait for Type` + /// + /// This is a "stability hack", not a real Rust feature. + /// See #64631 for details. + Reservation, +} + +impl fmt::Display for ImplPolarity { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Positive => f.write_str("positive"), + Self::Negative => f.write_str("negative"), + Self::Reservation => f.write_str("reservation"), + } + } +} + +/// Polarity for a trait predicate. May either be negative or positive. +/// Distinguished from [`ImplPolarity`] since we never compute goals with +/// "reservation" level. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub enum PredicatePolarity { + /// `Type: Trait` + Positive, + /// `Type: !Trait` + Negative, +} + +impl PredicatePolarity { + /// Flips polarity by turning `Positive` into `Negative` and `Negative` into `Positive`. + pub fn flip(&self) -> PredicatePolarity { + match self { + PredicatePolarity::Positive => PredicatePolarity::Negative, + PredicatePolarity::Negative => PredicatePolarity::Positive, + } + } +} + +impl fmt::Display for PredicatePolarity { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Positive => f.write_str("positive"), + Self::Negative => f.write_str("negative"), + } + } +} + +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub enum ExistentialPredicate { + /// E.g., `Iterator`. + Trait(ExistentialTraitRef), + /// E.g., `Iterator::Item = T`. + Projection(ExistentialProjection), + /// E.g., `Send`. + AutoTrait(I::DefId), +} + +// FIXME: Implement this the right way after +impl DebugWithInfcx for ExistentialPredicate { + fn fmt>( + this: rustc_type_ir::WithInfcx<'_, Infcx, &Self>, + f: &mut fmt::Formatter<'_>, + ) -> fmt::Result { + fmt::Debug::fmt(&this.data, f) + } +} + +/// An existential reference to a trait, where `Self` is erased. +/// For example, the trait object `Trait<'a, 'b, X, Y>` is: +/// ```ignore (illustrative) +/// exists T. T: Trait<'a, 'b, X, Y> +/// ``` +/// The generic parameters don't include the erased `Self`, only trait +/// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above). +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct ExistentialTraitRef { + pub def_id: I::DefId, + pub args: I::GenericArgs, +} + +impl ExistentialTraitRef { + pub fn erase_self_ty(interner: I, trait_ref: TraitRef) -> ExistentialTraitRef { + // Assert there is a Self. + trait_ref.args.type_at(0); + + ExistentialTraitRef { + def_id: trait_ref.def_id, + args: interner.mk_args(&trait_ref.args[1..]), + } + } + + /// Object types don't have a self type specified. Therefore, when + /// we convert the principal trait-ref into a normal trait-ref, + /// you must give *some* self type. A common choice is `mk_err()` + /// or some placeholder type. + pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> TraitRef { + // otherwise the escaping vars would be captured by the binder + // debug_assert!(!self_ty.has_escaping_bound_vars()); + + TraitRef::new( + interner, + self.def_id, + [self_ty.into()].into_iter().chain(self.args.into_iter()), + ) + } +} + +/// A `ProjectionPredicate` for an `ExistentialTraitRef`. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct ExistentialProjection { + pub def_id: I::DefId, + pub args: I::GenericArgs, + pub term: I::Term, +} + +impl ExistentialProjection { + /// Extracts the underlying existential trait reference from this projection. + /// For example, if this is a projection of `exists T. ::Item == X`, + /// then this function would return an `exists T. T: Iterator` existential trait + /// reference. + pub fn trait_ref(&self, tcx: I) -> ExistentialTraitRef { + let def_id = tcx.parent(self.def_id); + let args_count = tcx.generics_of(def_id).count() - 1; + let args = tcx.mk_args(&self.args[..args_count]); + ExistentialTraitRef { def_id, args } + } + + pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ProjectionPredicate { + // otherwise the escaping regions would be captured by the binders + debug_assert!(!self_ty.has_escaping_bound_vars()); + + ProjectionPredicate { + projection_ty: I::AliasTy::new( + tcx, + self.def_id, + [self_ty.into()].into_iter().chain(self.args), + ), + term: self.term, + } + } + + pub fn erase_self_ty(tcx: I, projection_predicate: ProjectionPredicate) -> Self { + // Assert there is a Self. + projection_predicate.projection_ty.args().type_at(0); + + Self { + def_id: projection_predicate.projection_ty.def_id(), + args: tcx.mk_args(&projection_predicate.projection_ty.args()[1..]), + term: projection_predicate.term, + } + } +} + +/// This kind of predicate has no *direct* correspondent in the +/// syntax, but it roughly corresponds to the syntactic forms: +/// +/// 1. `T: TraitRef<..., Item = Type>` +/// 2. `>::Item == Type` (NYI) +/// +/// In particular, form #1 is "desugared" to the combination of a +/// normal trait predicate (`T: TraitRef<...>`) and one of these +/// predicates. Form #2 is a broader form in that it also permits +/// equality between arbitrary types. Processing an instance of +/// Form #2 eventually yields one of these `ProjectionPredicate` +/// instances to normalize the LHS. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct ProjectionPredicate { + pub projection_ty: I::AliasTy, + pub term: I::Term, +} + +impl ProjectionPredicate { + pub fn self_ty(self) -> I::Ty { + self.projection_ty.self_ty() + } + + pub fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> ProjectionPredicate { + Self { projection_ty: self.projection_ty.with_self_ty(tcx, self_ty), ..self } + } + + pub fn trait_def_id(self, tcx: I) -> I::DefId { + self.projection_ty.trait_def_id(tcx) + } + + pub fn def_id(self) -> I::DefId { + self.projection_ty.def_id() + } +} + +impl fmt::Debug for ProjectionPredicate { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_ty, self.term) + } +} + +/// Used by the new solver. Unlike a `ProjectionPredicate` this can only be +/// proven by actually normalizing `alias`. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct NormalizesTo { + pub alias: I::AliasTy, + pub term: I::Term, +} + +impl NormalizesTo { + pub fn self_ty(self) -> I::Ty { + self.alias.self_ty() + } + + pub fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> NormalizesTo { + Self { alias: self.alias.with_self_ty(tcx, self_ty), ..self } + } + + pub fn trait_def_id(self, tcx: I) -> I::DefId { + self.alias.trait_def_id(tcx) + } + + pub fn def_id(self) -> I::DefId { + self.alias.def_id() + } +} + +impl fmt::Debug for NormalizesTo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "NormalizesTo({:?}, {:?})", self.alias, self.term) + } +} + +/// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates +/// whether the `a` type is the type that we should label as "expected" when +/// presenting user diagnostics. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct SubtypePredicate { + pub a_is_expected: bool, + pub a: I::Ty, + pub b: I::Ty, +} + +/// Encodes that we have to coerce *from* the `a` type to the `b` type. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub struct CoercePredicate { + pub a: I::Ty, + pub b: I::Ty, +} diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index 5260d9061cfc8..c477ab14153e2 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -1,17 +1,15 @@ -use rustc_ast_ir::try_visit; -use rustc_ast_ir::visit::VisitorResult; #[cfg(feature = "nightly")] use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use std::fmt; -use crate::fold::{FallibleTypeFolder, TypeFoldable}; -use crate::visit::{TypeVisitable, TypeVisitor}; use crate::Interner; /// A clause is something that can appear in where bounds or be inferred /// by implied bounds. #[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""))] +#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum ClauseKind { /// Corresponds to `where Foo: Bar`. `Foo` here would be @@ -55,61 +53,6 @@ impl PartialEq for ClauseKind { } } -impl Eq for ClauseKind {} - -impl TypeFoldable for ClauseKind -where - I::Ty: TypeFoldable, - I::Const: TypeFoldable, - I::GenericArg: TypeFoldable, - I::TraitPredicate: TypeFoldable, - I::ProjectionPredicate: TypeFoldable, - I::TypeOutlivesPredicate: TypeFoldable, - I::RegionOutlivesPredicate: TypeFoldable, -{ - fn try_fold_with>(self, folder: &mut F) -> Result { - Ok(match self { - ClauseKind::Trait(p) => ClauseKind::Trait(p.try_fold_with(folder)?), - ClauseKind::RegionOutlives(p) => ClauseKind::RegionOutlives(p.try_fold_with(folder)?), - ClauseKind::TypeOutlives(p) => ClauseKind::TypeOutlives(p.try_fold_with(folder)?), - ClauseKind::Projection(p) => ClauseKind::Projection(p.try_fold_with(folder)?), - ClauseKind::ConstArgHasType(c, t) => { - ClauseKind::ConstArgHasType(c.try_fold_with(folder)?, t.try_fold_with(folder)?) - } - ClauseKind::WellFormed(p) => ClauseKind::WellFormed(p.try_fold_with(folder)?), - ClauseKind::ConstEvaluatable(p) => { - ClauseKind::ConstEvaluatable(p.try_fold_with(folder)?) - } - }) - } -} - -impl TypeVisitable for ClauseKind -where - I::Ty: TypeVisitable, - I::Const: TypeVisitable, - I::GenericArg: TypeVisitable, - I::TraitPredicate: TypeVisitable, - I::ProjectionPredicate: TypeVisitable, - I::TypeOutlivesPredicate: TypeVisitable, - I::RegionOutlivesPredicate: TypeVisitable, -{ - fn visit_with>(&self, visitor: &mut V) -> V::Result { - match self { - ClauseKind::Trait(p) => p.visit_with(visitor), - ClauseKind::RegionOutlives(p) => p.visit_with(visitor), - ClauseKind::TypeOutlives(p) => p.visit_with(visitor), - ClauseKind::Projection(p) => p.visit_with(visitor), - ClauseKind::ConstArgHasType(c, t) => { - try_visit!(c.visit_with(visitor)); - t.visit_with(visitor) - } - ClauseKind::WellFormed(p) => p.visit_with(visitor), - ClauseKind::ConstEvaluatable(p) => p.visit_with(visitor), - } - } -} - #[derive(derivative::Derivative)] #[derivative( Clone(bound = ""), @@ -118,6 +61,7 @@ where PartialEq(bound = ""), Eq(bound = "") )] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum PredicateKind { /// Prove a clause @@ -167,69 +111,6 @@ pub enum PredicateKind { AliasRelate(I::Term, I::Term, AliasRelationDirection), } -impl TypeFoldable for PredicateKind -where - I::DefId: TypeFoldable, - I::Const: TypeFoldable, - I::GenericArgs: TypeFoldable, - I::Term: TypeFoldable, - I::CoercePredicate: TypeFoldable, - I::SubtypePredicate: TypeFoldable, - I::NormalizesTo: TypeFoldable, - ClauseKind: TypeFoldable, -{ - fn try_fold_with>(self, folder: &mut F) -> Result { - Ok(match self { - PredicateKind::Clause(c) => PredicateKind::Clause(c.try_fold_with(folder)?), - PredicateKind::ObjectSafe(d) => PredicateKind::ObjectSafe(d.try_fold_with(folder)?), - PredicateKind::Subtype(s) => PredicateKind::Subtype(s.try_fold_with(folder)?), - PredicateKind::Coerce(s) => PredicateKind::Coerce(s.try_fold_with(folder)?), - PredicateKind::ConstEquate(a, b) => { - PredicateKind::ConstEquate(a.try_fold_with(folder)?, b.try_fold_with(folder)?) - } - PredicateKind::Ambiguous => PredicateKind::Ambiguous, - PredicateKind::NormalizesTo(p) => PredicateKind::NormalizesTo(p.try_fold_with(folder)?), - PredicateKind::AliasRelate(a, b, d) => PredicateKind::AliasRelate( - a.try_fold_with(folder)?, - b.try_fold_with(folder)?, - d.try_fold_with(folder)?, - ), - }) - } -} - -impl TypeVisitable for PredicateKind -where - I::DefId: TypeVisitable, - I::Const: TypeVisitable, - I::GenericArgs: TypeVisitable, - I::Term: TypeVisitable, - I::CoercePredicate: TypeVisitable, - I::SubtypePredicate: TypeVisitable, - I::NormalizesTo: TypeVisitable, - ClauseKind: TypeVisitable, -{ - fn visit_with>(&self, visitor: &mut V) -> V::Result { - match self { - PredicateKind::Clause(p) => p.visit_with(visitor), - PredicateKind::ObjectSafe(d) => d.visit_with(visitor), - PredicateKind::Subtype(s) => s.visit_with(visitor), - PredicateKind::Coerce(s) => s.visit_with(visitor), - PredicateKind::ConstEquate(a, b) => { - try_visit!(a.visit_with(visitor)); - b.visit_with(visitor) - } - PredicateKind::Ambiguous => V::Result::output(), - PredicateKind::NormalizesTo(p) => p.visit_with(visitor), - PredicateKind::AliasRelate(a, b, d) => { - try_visit!(a.visit_with(visitor)); - try_visit!(b.visit_with(visitor)); - d.visit_with(visitor) - } - } - } -} - #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext, Encodable, Decodable))] pub enum AliasRelationDirection { diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index d1b86b495e9d8..eaae4ee0130bf 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -115,7 +115,7 @@ use self::RegionKind::*; /// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html #[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""))] +#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))] pub enum RegionKind { /// A region parameter; for example `'a` in `impl<'a> Trait for &'a ()`. @@ -208,9 +208,6 @@ impl PartialEq for RegionKind { } } -// This is manually implemented because a derive would require `I: Eq` -impl Eq for RegionKind {} - impl DebugWithInfcx for RegionKind { fn fmt>( this: WithInfcx<'_, Infcx, &Self>, diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index f2e4afecc4025..d67327926ff3b 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -1,14 +1,12 @@ -use rustc_ast_ir::try_visit; #[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; #[cfg(feature = "nightly")] use rustc_data_structures::unify::{EqUnifyValue, UnifyKey}; #[cfg(feature = "nightly")] use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use std::fmt; -use crate::fold::{FallibleTypeFolder, TypeFoldable}; -use crate::visit::{TypeVisitable, TypeVisitor}; use crate::Interner; use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, WithInfcx}; @@ -65,7 +63,7 @@ impl AliasKind { /// converted to this representation using `::lower_ty`. #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "IrTyKind")] #[derive(derivative::Derivative)] -#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""))] +#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] pub enum TyKind { /// The primitive boolean type. Written as `bool`. @@ -341,9 +339,6 @@ impl PartialEq for TyKind { } } -// This is manually implemented because a derive would require `I: Eq` -impl Eq for TyKind {} - impl DebugWithInfcx for TyKind { fn fmt>( this: WithInfcx<'_, Infcx, &Self>, @@ -804,29 +799,8 @@ impl DebugWithInfcx for InferTy { Debug(bound = "") )] #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] pub struct TypeAndMut { pub ty: I::Ty, pub mutbl: Mutability, } - -impl TypeFoldable for TypeAndMut -where - I::Ty: TypeFoldable, -{ - fn try_fold_with>(self, folder: &mut F) -> Result { - Ok(TypeAndMut { - ty: self.ty.try_fold_with(folder)?, - mutbl: self.mutbl.try_fold_with(folder)?, - }) - } -} - -impl TypeVisitable for TypeAndMut -where - I::Ty: TypeVisitable, -{ - fn visit_with>(&self, visitor: &mut V) -> V::Result { - try_visit!(self.ty.visit_with(visitor)); - self.mutbl.visit_with(visitor) - } -} diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 2f588c67f5698..3d4125f600ef8 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -47,7 +47,8 @@ use rustc_index::{Idx, IndexVec}; use std::fmt; use std::ops::ControlFlow; -use crate::{self as ty, BoundVars, Interner, IntoKind, Lrc, TypeFlags}; +use crate::inherent::*; +use crate::{self as ty, Interner, Lrc, TypeFlags}; /// This trait is implemented for every type that can be visited, /// providing the skeleton of the traversal. diff --git a/compiler/rustc_type_ir_macros/Cargo.toml b/compiler/rustc_type_ir_macros/Cargo.toml new file mode 100644 index 0000000000000..cb95ca6834623 --- /dev/null +++ b/compiler/rustc_type_ir_macros/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "rustc_type_ir_macros" +version = "0.0.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +# tidy-alphabetical-start +proc-macro2 = "1" +quote = "1" +syn = { version = "2.0.9", features = ["full"] } +synstructure = "0.13.0" +# tidy-alphabetical-end diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs new file mode 100644 index 0000000000000..000bcf2d3b27d --- /dev/null +++ b/compiler/rustc_type_ir_macros/src/lib.rs @@ -0,0 +1,159 @@ +use quote::quote; +use syn::{parse_quote, visit_mut::VisitMut}; +use synstructure::decl_derive; + +decl_derive!( + [TypeFoldable_Generic] => type_foldable_derive +); +decl_derive!( + [TypeVisitable_Generic] => type_visitable_derive +); +decl_derive!( + [Lift_Generic] => lift_derive +); + +fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + if let syn::Data::Union(_) = s.ast().data { + panic!("cannot derive on union") + } + + if !s.ast().generics.type_params().any(|ty| ty.ident == "I") { + s.add_impl_generic(parse_quote! { I }); + } + + s.add_where_predicate(parse_quote! { I: Interner }); + s.add_bounds(synstructure::AddBounds::Fields); + s.bind_with(|_| synstructure::BindStyle::Move); + let body_fold = s.each_variant(|vi| { + let bindings = vi.bindings(); + vi.construct(|_, index| { + let bind = &bindings[index]; + quote! { + ::rustc_type_ir::fold::TypeFoldable::try_fold_with(#bind, __folder)? + } + }) + }); + + s.bound_impl( + quote!(::rustc_type_ir::fold::TypeFoldable), + quote! { + fn try_fold_with<__F: ::rustc_type_ir::fold::FallibleTypeFolder>( + self, + __folder: &mut __F + ) -> Result { + Ok(match self { #body_fold }) + } + }, + ) +} + +fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + if let syn::Data::Union(_) = s.ast().data { + panic!("cannot derive on union") + } + + if !s.ast().generics.type_params().any(|ty| ty.ident == "I") { + s.add_impl_generic(parse_quote! { I }); + } + + s.add_bounds(synstructure::AddBounds::None); + s.add_where_predicate(parse_quote! { I: Interner }); + s.add_impl_generic(parse_quote! { J }); + s.add_where_predicate(parse_quote! { J: Interner }); + + let mut wc = vec![]; + s.bind_with(|_| synstructure::BindStyle::Move); + let body_fold = s.each_variant(|vi| { + let bindings = vi.bindings(); + vi.construct(|field, index| { + let ty = field.ty.clone(); + let lifted_ty = lift(ty.clone()); + wc.push(parse_quote! { #ty: ::rustc_type_ir::lift::Lift }); + let bind = &bindings[index]; + quote! { + #bind.lift_to_tcx(interner)? + } + }) + }); + for wc in wc { + s.add_where_predicate(wc); + } + + let (_, ty_generics, _) = s.ast().generics.split_for_impl(); + let name = s.ast().ident.clone(); + let self_ty: syn::Type = parse_quote! { #name #ty_generics }; + let lifted_ty = lift(self_ty); + + s.bound_impl( + quote!(::rustc_type_ir::lift::Lift), + quote! { + type Lifted = #lifted_ty; + + fn lift_to_tcx( + self, + interner: J, + ) -> Option { + Some(match self { #body_fold }) + } + }, + ) +} + +fn lift(mut ty: syn::Type) -> syn::Type { + struct ItoJ; + impl VisitMut for ItoJ { + fn visit_type_path_mut(&mut self, i: &mut syn::TypePath) { + if i.qself.is_none() { + if let Some(first) = i.path.segments.first_mut() { + if first.ident == "I" { + *first = parse_quote! { J }; + } + } + } + syn::visit_mut::visit_type_path_mut(self, i); + } + } + + ItoJ.visit_type_mut(&mut ty); + + ty +} + +fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + if let syn::Data::Union(_) = s.ast().data { + panic!("cannot derive on union") + } + + if !s.ast().generics.type_params().any(|ty| ty.ident == "I") { + s.add_impl_generic(parse_quote! { I }); + } + + s.add_where_predicate(parse_quote! { I: Interner }); + s.add_bounds(synstructure::AddBounds::Fields); + let body_visit = s.each(|bind| { + quote! { + match ::rustc_ast_ir::visit::VisitorResult::branch( + ::rustc_type_ir::visit::TypeVisitable::visit_with(#bind, __visitor) + ) { + ::core::ops::ControlFlow::Continue(()) => {}, + ::core::ops::ControlFlow::Break(r) => { + return ::rustc_ast_ir::visit::VisitorResult::from_residual(r); + }, + } + } + }); + s.bind_with(|_| synstructure::BindStyle::Move); + + s.bound_impl( + quote!(::rustc_type_ir::visit::TypeVisitable), + quote! { + fn visit_with<__V: ::rustc_type_ir::visit::TypeVisitor>( + &self, + __visitor: &mut __V + ) -> __V::Result { + match *self { #body_visit } + <__V::Result as ::rustc_ast_ir::visit::VisitorResult>::output() + } + }, + ) +} diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs index 92bc2e34561ae..e1c14fe0b380b 100644 --- a/compiler/stable_mir/src/abi.rs +++ b/compiler/stable_mir/src/abi.rs @@ -6,7 +6,7 @@ use crate::ty::{Align, IndexedVal, Ty, VariantIdx}; use crate::Error; use crate::Opaque; use std::fmt::{self, Debug}; -use std::num::NonZeroUsize; +use std::num::NonZero; use std::ops::RangeInclusive; /// A function ABI definition. @@ -133,7 +133,7 @@ pub enum FieldsShape { Primitive, /// All fields start at no offset. The `usize` is the field count. - Union(NonZeroUsize), + Union(NonZero), /// Array/vector-like placement, with all fields of identical types. Array { stride: Size, count: u64 }, diff --git a/config.example.toml b/config.example.toml index 3b76952504f28..224d079b20699 100644 --- a/config.example.toml +++ b/config.example.toml @@ -213,17 +213,17 @@ # the root of the repository. #build-dir = "build" -# Instead of downloading the src/stage0.json version of Cargo specified, use +# Instead of downloading the src/stage0 version of Cargo specified, use # this Cargo binary instead to build all Rust code # If you set this, you likely want to set `rustc` as well. #cargo = "/path/to/cargo" -# Instead of downloading the src/stage0.json version of the compiler +# Instead of downloading the src/stage0 version of the compiler # specified, use this rustc binary instead as the stage0 snapshot compiler. # If you set this, you likely want to set `cargo` as well. #rustc = "/path/to/rustc" -# Instead of downloading the src/stage0.json version of rustfmt specified, +# Instead of downloading the src/stage0 version of rustfmt specified, # use this rustfmt binary instead as the stage0 snapshot rustfmt. #rustfmt = "/path/to/rustfmt" diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index f143e5578717f..b13af93d06c57 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -910,6 +910,19 @@ impl From<&CStr> for Rc { } } +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")] +impl Default for Rc { + /// Creates an empty CStr inside an Rc + /// + /// This may or may not share an allocation with other Rcs on the same thread. + #[inline] + fn default() -> Self { + let c_str: &CStr = Default::default(); + Rc::from(c_str) + } +} + #[cfg(not(test))] #[stable(feature = "default_box_extra", since = "1.17.0")] impl Default for Box { diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index b9918752540f3..ae44cab8131b5 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -403,7 +403,7 @@ //! is, a formatting implementation must and may only return an error if the //! passed-in [`Formatter`] returns an error. This is because, contrary to what //! the function signature might suggest, string formatting is an infallible -//! operation. This function only returns a result because writing to the +//! operation. This function only returns a [`Result`] because writing to the //! underlying stream might fail and it must provide a way to propagate the fact //! that an error has occurred back up the stack. //! @@ -630,7 +630,9 @@ pub fn format(args: Arguments<'_>) -> string::String { fn format_inner(args: Arguments<'_>) -> string::String { let capacity = args.estimated_capacity(); let mut output = string::String::with_capacity(capacity); - output.write_fmt(args).expect("a formatting trait implementation returned an error"); + output + .write_fmt(args) + .expect("a formatting trait implementation returned an error when the underlying stream did not"); output } diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index c245b42c3e880..dddd0603a1506 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -365,6 +365,12 @@ impl Rc { unsafe { self.ptr.as_ref() } } + #[inline] + fn into_inner_with_allocator(this: Self) -> (NonNull>, A) { + let this = mem::ManuallyDrop::new(this); + (this.ptr, unsafe { ptr::read(&this.alloc) }) + } + #[inline] unsafe fn from_inner_in(ptr: NonNull>, alloc: A) -> Self { Self { ptr, phantom: PhantomData, alloc } @@ -1145,12 +1151,9 @@ impl Rc, A> { /// ``` #[unstable(feature = "new_uninit", issue = "63291")] #[inline] - pub unsafe fn assume_init(self) -> Rc - where - A: Clone, - { - let md_self = mem::ManuallyDrop::new(self); - unsafe { Rc::from_inner_in(md_self.ptr.cast(), md_self.alloc.clone()) } + pub unsafe fn assume_init(self) -> Rc { + let (ptr, alloc) = Rc::into_inner_with_allocator(self); + unsafe { Rc::from_inner_in(ptr.cast(), alloc) } } } @@ -1189,12 +1192,9 @@ impl Rc<[mem::MaybeUninit], A> { /// ``` #[unstable(feature = "new_uninit", issue = "63291")] #[inline] - pub unsafe fn assume_init(self) -> Rc<[T], A> - where - A: Clone, - { - let md_self = mem::ManuallyDrop::new(self); - unsafe { Rc::from_ptr_in(md_self.ptr.as_ptr() as _, md_self.alloc.clone()) } + pub unsafe fn assume_init(self) -> Rc<[T], A> { + let (ptr, alloc) = Rc::into_inner_with_allocator(self); + unsafe { Rc::from_ptr_in(ptr.as_ptr() as _, alloc) } } } @@ -1809,7 +1809,9 @@ impl Rc { // reference to the allocation. unsafe { &mut this.ptr.as_mut().value } } +} +impl Rc { /// If we have the only reference to `T` then unwrap it. Otherwise, clone `T` and return the /// clone. /// @@ -1845,7 +1847,7 @@ impl Rc { } } -impl Rc { +impl Rc { /// Attempt to downcast the `Rc` to a concrete type. /// /// # Examples @@ -1869,10 +1871,8 @@ impl Rc { pub fn downcast(self) -> Result, Self> { if (*self).is::() { unsafe { - let ptr = self.ptr.cast::>(); - let alloc = self.alloc.clone(); - forget(self); - Ok(Rc::from_inner_in(ptr, alloc)) + let (ptr, alloc) = Rc::into_inner_with_allocator(self); + Ok(Rc::from_inner_in(ptr.cast(), alloc)) } } else { Err(self) @@ -1909,10 +1909,8 @@ impl Rc { #[unstable(feature = "downcast_unchecked", issue = "90850")] pub unsafe fn downcast_unchecked(self) -> Rc { unsafe { - let ptr = self.ptr.cast::>(); - let alloc = self.alloc.clone(); - mem::forget(self); - Rc::from_inner_in(ptr, alloc) + let (ptr, alloc) = Rc::into_inner_with_allocator(self); + Rc::from_inner_in(ptr.cast(), alloc) } } } @@ -2226,6 +2224,31 @@ impl Default for Rc { } } +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")] +impl Default for Rc { + /// Creates an empty str inside an Rc + /// + /// This may or may not share an allocation with other Rcs on the same thread. + #[inline] + fn default() -> Self { + Rc::from("") + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")] +impl Default for Rc<[T]> { + /// Creates an empty `[T]` inside an Rc + /// + /// This may or may not share an allocation with other Rcs on the same thread. + #[inline] + fn default() -> Self { + let arr: [T; 0] = []; + Rc::from(arr) + } +} + #[stable(feature = "rust1", since = "1.0.0")] trait RcEqIdent { fn eq(&self, other: &Rc) -> bool; @@ -2661,12 +2684,13 @@ impl From> for Rc<[u8]> { } #[stable(feature = "boxed_slice_try_from", since = "1.43.0")] -impl TryFrom> for Rc<[T; N]> { - type Error = Rc<[T]>; +impl TryFrom> for Rc<[T; N], A> { + type Error = Rc<[T], A>; - fn try_from(boxed_slice: Rc<[T]>) -> Result { + fn try_from(boxed_slice: Rc<[T], A>) -> Result { if boxed_slice.len() == N { - Ok(unsafe { Rc::from_raw(Rc::into_raw(boxed_slice) as *mut [T; N]) }) + let (ptr, alloc) = Rc::into_inner_with_allocator(boxed_slice); + Ok(unsafe { Rc::from_inner_in(ptr.cast(), alloc) }) } else { Err(boxed_slice) } diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index c0d292cd20886..3e23612d0c13c 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -375,14 +375,16 @@ impl str { // Safety: We have written only valid ASCII to our vec let mut s = unsafe { String::from_utf8_unchecked(out) }; - for (i, c) in rest[..].char_indices() { + for (i, c) in rest.char_indices() { if c == 'Σ' { // Σ maps to σ, except at the end of a word where it maps to ς. // This is the only conditional (contextual) but language-independent mapping // in `SpecialCasing.txt`, // so hard-code it rather than have a generic "condition" mechanism. // See https://github.com/rust-lang/rust/issues/26035 - map_uppercase_sigma(rest, i, &mut s) + let out_len = self.len() - rest.len(); + let sigma_lowercase = map_uppercase_sigma(&self, i + out_len); + s.push(sigma_lowercase); } else { match conversions::to_lower(c) { [a, '\0', _] => s.push(a), @@ -400,13 +402,13 @@ impl str { } return s; - fn map_uppercase_sigma(from: &str, i: usize, to: &mut String) { + fn map_uppercase_sigma(from: &str, i: usize) -> char { // See https://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992 // for the definition of `Final_Sigma`. debug_assert!('Σ'.len_utf8() == 2); let is_word_final = case_ignorable_then_cased(from[..i].chars().rev()) && !case_ignorable_then_cased(from[i + 2..].chars()); - to.push_str(if is_word_final { "ς" } else { "σ" }); + if is_word_final { 'ς' } else { 'σ' } } fn case_ignorable_then_cased>(iter: I) -> bool { diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 297a273d274bf..a925b544bc2c9 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -280,8 +280,8 @@ impl Arc { impl Arc { #[inline] - fn internal_into_inner_with_allocator(self) -> (NonNull>, A) { - let this = mem::ManuallyDrop::new(self); + fn into_inner_with_allocator(this: Self) -> (NonNull>, A) { + let this = mem::ManuallyDrop::new(this); (this.ptr, unsafe { ptr::read(&this.alloc) }) } @@ -1290,7 +1290,7 @@ impl Arc, A> { #[must_use = "`self` will be dropped if the result is not used"] #[inline] pub unsafe fn assume_init(self) -> Arc { - let (ptr, alloc) = self.internal_into_inner_with_allocator(); + let (ptr, alloc) = Arc::into_inner_with_allocator(self); unsafe { Arc::from_inner_in(ptr.cast(), alloc) } } } @@ -1332,7 +1332,7 @@ impl Arc<[mem::MaybeUninit], A> { #[must_use = "`self` will be dropped if the result is not used"] #[inline] pub unsafe fn assume_init(self) -> Arc<[T], A> { - let (ptr, alloc) = self.internal_into_inner_with_allocator(); + let (ptr, alloc) = Arc::into_inner_with_allocator(self); unsafe { Arc::from_ptr_in(ptr.as_ptr() as _, alloc) } } } @@ -2227,7 +2227,9 @@ impl Arc { // either unique to begin with, or became one upon cloning the contents. unsafe { Self::get_mut_unchecked(this) } } +} +impl Arc { /// If we have the only reference to `T` then unwrap it. Otherwise, clone `T` and return the /// clone. /// @@ -2499,7 +2501,7 @@ impl Arc { { if (*self).is::() { unsafe { - let (ptr, alloc) = self.internal_into_inner_with_allocator(); + let (ptr, alloc) = Arc::into_inner_with_allocator(self); Ok(Arc::from_inner_in(ptr.cast(), alloc)) } } else { @@ -2540,7 +2542,7 @@ impl Arc { T: Any + Send + Sync, { unsafe { - let (ptr, alloc) = self.internal_into_inner_with_allocator(); + let (ptr, alloc) = Arc::into_inner_with_allocator(self); Arc::from_inner_in(ptr.cast(), alloc) } } @@ -3298,6 +3300,81 @@ impl Default for Arc { } } +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")] +impl Default for Arc { + /// Creates an empty str inside an Arc + /// + /// This may or may not share an allocation with other Arcs. + #[inline] + fn default() -> Self { + let arc: Arc<[u8]> = Default::default(); + debug_assert!(core::str::from_utf8(&*arc).is_ok()); + let (ptr, alloc) = Arc::into_inner_with_allocator(arc); + unsafe { Arc::from_ptr_in(ptr.as_ptr() as *mut ArcInner, alloc) } + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")] +impl Default for Arc { + /// Creates an empty CStr inside an Arc + /// + /// This may or may not share an allocation with other Arcs. + #[inline] + fn default() -> Self { + use core::ffi::CStr; + static STATIC_INNER_CSTR: ArcInner<[u8; 1]> = ArcInner { + strong: atomic::AtomicUsize::new(1), + weak: atomic::AtomicUsize::new(1), + data: [0], + }; + let inner: NonNull> = NonNull::from(&STATIC_INNER_CSTR); + let inner: NonNull> = NonNull::new(inner.as_ptr() as *mut ArcInner).unwrap(); + // `this` semantically is the Arc "owned" by the static, so make sure not to drop it. + let this: mem::ManuallyDrop> = unsafe { mem::ManuallyDrop::new(Arc::from_inner(inner)) }; + (*this).clone() + } +} + +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")] +impl Default for Arc<[T]> { + /// Creates an empty `[T]` inside an Arc + /// + /// This may or may not share an allocation with other Arcs. + #[inline] + fn default() -> Self { + let alignment_of_t: usize = mem::align_of::(); + // We only make statics for the lowest five alignments. + // Alignments greater than that will use dynamic allocation. + macro_rules! use_static_inner_for_alignments { + ($($alignment:literal),*) => { + $(if alignment_of_t == $alignment { + // Note: this must be in a new scope because static and type names are unhygenic. + #[repr(align($alignment))] + struct Aligned; + static ALIGNED_STATIC_INNER: ArcInner = ArcInner { + strong: atomic::AtomicUsize::new(1), + weak: atomic::AtomicUsize::new(1), + data: Aligned, + }; + let inner: NonNull> = NonNull::from(&ALIGNED_STATIC_INNER); + let inner: NonNull> = inner.cast(); + // `this` semantically is the Arc "owned" by the static, so make sure not to drop it. + let this: mem::ManuallyDrop> = unsafe { mem::ManuallyDrop::new(Arc::from_inner(inner)) }; + return (*this).clone(); + })* + }; + } + use_static_inner_for_alignments!(1, 2, 4, 8, 16); + + // If T's alignment is not one of the ones we have a static for, make a new unique allocation. + let arr: [T; 0] = []; + Arc::from(arr) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Hash for Arc { fn hash(&self, state: &mut H) { @@ -3506,7 +3583,7 @@ impl TryFrom> for Arc<[T; N], A> { fn try_from(boxed_slice: Arc<[T], A>) -> Result { if boxed_slice.len() == N { - let (ptr, alloc) = boxed_slice.internal_into_inner_with_allocator(); + let (ptr, alloc) = Arc::into_inner_with_allocator(boxed_slice); Ok(unsafe { Arc::from_inner_in(ptr.cast(), alloc) }) } else { Err(boxed_slice) diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index df8a260624a28..0078f5eaa3d2b 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1848,6 +1848,9 @@ fn to_lowercase() { assert_eq!("ΑΣ'Α".to_lowercase(), "ασ'α"); assert_eq!("ΑΣ''Α".to_lowercase(), "ασ''α"); + // https://github.com/rust-lang/rust/issues/124714 + assert_eq!("abcdefghijklmnopΣ".to_lowercase(), "abcdefghijklmnopς"); + // a really long string that has it's lowercase form // even longer. this tests that implementations don't assume // an incorrect upper bound on allocations diff --git a/library/core/benches/str.rs b/library/core/benches/str.rs index 7d36eff3d6c8b..0f14809444bc5 100644 --- a/library/core/benches/str.rs +++ b/library/core/benches/str.rs @@ -3,6 +3,7 @@ use test::{black_box, Bencher}; mod char_count; mod corpora; +mod debug; mod iter; #[bench] diff --git a/library/core/benches/str/debug.rs b/library/core/benches/str/debug.rs new file mode 100644 index 0000000000000..7c72228f0fb5b --- /dev/null +++ b/library/core/benches/str/debug.rs @@ -0,0 +1,79 @@ +//! This primarily benchmarks `impl Debug for str`, +//! and it also explicitly tests that we minimizes calls to the underlying `Write`r. +//! While that is an implementation detail and there are no guarantees about it, +//! we should still try to minimize those calls over time rather than regress them. + +use std::fmt::{self, Write}; +use test::{black_box, Bencher}; + +#[derive(Default)] +struct CountingWriter { + buf: String, + write_calls: usize, +} + +impl Write for CountingWriter { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.buf.push_str(s); + self.write_calls += 1; + Ok(()) + } +} + +fn assert_fmt(s: &str, expected: &str, expected_write_calls: usize) { + let mut w = CountingWriter::default(); + + write!(&mut w, "{s:?}").unwrap(); + assert_eq!(s.len(), 64); + assert_eq!(w.buf, expected); + assert_eq!(w.write_calls, expected_write_calls); +} + +#[bench] +fn ascii_only(b: &mut Bencher) { + let s = "just a bit of ascii text that has no escapes. 64 bytes exactly!!"; + assert_fmt(s, r#""just a bit of ascii text that has no escapes. 64 bytes exactly!!""#, 3); + b.iter(|| { + black_box(format!("{:?}", black_box(s))); + }); +} + +#[bench] +fn ascii_escapes(b: &mut Bencher) { + let s = "some\tmore\tascii\ttext\nthis time with some \"escapes\", also 64 byte"; + assert_fmt( + s, + r#""some\tmore\tascii\ttext\nthis time with some \"escapes\", also 64 byte""#, + 21, + ); + b.iter(|| { + black_box(format!("{:?}", black_box(s))); + }); +} + +#[bench] +fn some_unicode(b: &mut Bencher) { + let s = "egy kis szöveg néhány unicode betűvel. legyen ez is 64 byte."; + assert_fmt(s, r#""egy kis szöveg néhány unicode betűvel. legyen ez is 64 byte.""#, 3); + b.iter(|| { + black_box(format!("{:?}", black_box(s))); + }); +} + +#[bench] +fn mostly_unicode(b: &mut Bencher) { + let s = "предложение из кириллических букв."; + assert_fmt(s, r#""предложение из кириллических букв.""#, 3); + b.iter(|| { + black_box(format!("{:?}", black_box(s))); + }); +} + +#[bench] +fn mixed(b: &mut Bencher) { + let s = "\"❤️\"\n\"hűha ez betű\"\n\"кириллических букв\"."; + assert_fmt(s, r#""\"❤\u{fe0f}\"\n\"hűha ez betű\"\n\"кириллических букв\".""#, 36); + b.iter(|| { + black_box(format!("{:?}", black_box(s))); + }); +} diff --git a/library/core/src/fmt/fmt_trait_method_doc.md b/library/core/src/fmt/fmt_trait_method_doc.md new file mode 100644 index 0000000000000..493d929243d2d --- /dev/null +++ b/library/core/src/fmt/fmt_trait_method_doc.md @@ -0,0 +1,8 @@ +Formats the value using the given formatter. + +# Errors + +This function should return [`Err`] if, and only if, the provided [`Formatter`] returns [`Err`]. +String formatting is considered an infallible operation; this function only +returns a [`Result`] because writing to the underlying stream might fail and it must +provide a way to propagate the fact that an error has occurred back up the stack. diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index ce0643a3f5ef5..9b372eac52455 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -72,14 +72,24 @@ pub type Result = result::Result<(), Error>; /// The error type which is returned from formatting a message into a stream. /// /// This type does not support transmission of an error other than that an error -/// occurred. Any extra information must be arranged to be transmitted through -/// some other means. -/// -/// An important thing to remember is that the type `fmt::Error` should not be +/// occurred. This is because, despite the existence of this error, +/// string formatting is considered an infallible operation. +/// `fmt()` implementors should not return this `Error` unless they received it from their +/// [`Formatter`]. The only time your code should create a new instance of this +/// error is when implementing `fmt::Write`, in order to cancel the formatting operation when +/// writing to the underlying stream fails. +/// +/// Any extra information must be arranged to be transmitted through some other means, +/// such as storing it in a field to be consulted after the formatting operation has been +/// cancelled. (For example, this is how [`std::io::Write::write_fmt()`] propagates IO errors +/// during writing.) +/// +/// This type, `fmt::Error`, should not be /// confused with [`std::io::Error`] or [`std::error::Error`], which you may also /// have in scope. /// /// [`std::io::Error`]: ../../std/io/struct.Error.html +/// [`std::io::Write::write_fmt()`]: ../../std/io/trait.Write.html#method.write_fmt /// [`std::error::Error`]: ../../std/error/trait.Error.html /// /// # Examples @@ -118,8 +128,10 @@ pub trait Write { /// This function will return an instance of [`std::fmt::Error`][Error] on error. /// /// The purpose of that error is to abort the formatting operation when the underlying - /// destination encounters some error preventing it from accepting more text; it should - /// generally be propagated rather than handled, at least when implementing formatting traits. + /// destination encounters some error preventing it from accepting more text; + /// in particular, it does not communicate any information about *what* error occurred. + /// It should generally be propagated rather than handled, at least when implementing + /// formatting traits. /// /// # Examples /// @@ -586,7 +598,7 @@ impl Display for Arguments<'_> { #[rustc_diagnostic_item = "Debug"] #[rustc_trivial_field_reads] pub trait Debug { - /// Formats the value using the given formatter. + #[doc = include_str!("fmt_trait_method_doc.md")] /// /// # Examples /// @@ -703,7 +715,7 @@ pub use macros::Debug; #[rustc_diagnostic_item = "Display"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Display { - /// Formats the value using the given formatter. + #[doc = include_str!("fmt_trait_method_doc.md")] /// /// # Examples /// @@ -777,7 +789,7 @@ pub trait Display { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait Octal { - /// Formats the value using the given formatter. + #[doc = include_str!("fmt_trait_method_doc.md")] #[stable(feature = "rust1", since = "1.0.0")] fn fmt(&self, f: &mut Formatter<'_>) -> Result; } @@ -836,7 +848,7 @@ pub trait Octal { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait Binary { - /// Formats the value using the given formatter. + #[doc = include_str!("fmt_trait_method_doc.md")] #[stable(feature = "rust1", since = "1.0.0")] fn fmt(&self, f: &mut Formatter<'_>) -> Result; } @@ -891,7 +903,7 @@ pub trait Binary { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait LowerHex { - /// Formats the value using the given formatter. + #[doc = include_str!("fmt_trait_method_doc.md")] #[stable(feature = "rust1", since = "1.0.0")] fn fmt(&self, f: &mut Formatter<'_>) -> Result; } @@ -946,7 +958,7 @@ pub trait LowerHex { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait UpperHex { - /// Formats the value using the given formatter. + #[doc = include_str!("fmt_trait_method_doc.md")] #[stable(feature = "rust1", since = "1.0.0")] fn fmt(&self, f: &mut Formatter<'_>) -> Result; } @@ -997,7 +1009,7 @@ pub trait UpperHex { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Pointer"] pub trait Pointer { - /// Formats the value using the given formatter. + #[doc = include_str!("fmt_trait_method_doc.md")] #[stable(feature = "rust1", since = "1.0.0")] fn fmt(&self, f: &mut Formatter<'_>) -> Result; } @@ -1048,7 +1060,7 @@ pub trait Pointer { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait LowerExp { - /// Formats the value using the given formatter. + #[doc = include_str!("fmt_trait_method_doc.md")] #[stable(feature = "rust1", since = "1.0.0")] fn fmt(&self, f: &mut Formatter<'_>) -> Result; } @@ -1099,7 +1111,7 @@ pub trait LowerExp { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub trait UpperExp { - /// Formats the value using the given formatter. + #[doc = include_str!("fmt_trait_method_doc.md")] #[stable(feature = "rust1", since = "1.0.0")] fn fmt(&self, f: &mut Formatter<'_>) -> Result; } diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs index a5cf069d407c0..abdf2f415fe55 100644 --- a/library/core/src/iter/adapters/step_by.rs +++ b/library/core/src/iter/adapters/step_by.rs @@ -1,7 +1,7 @@ use crate::{ intrinsics, iter::{from_fn, TrustedLen, TrustedRandomAccess}, - num::NonZeroUsize, + num::NonZero, ops::{Range, Try}, }; @@ -42,10 +42,10 @@ impl StepBy { /// The `step` that was originally passed to `Iterator::step_by(step)`, /// aka `self.step_minus_one + 1`. #[inline] - fn original_step(&self) -> NonZeroUsize { + fn original_step(&self) -> NonZero { // 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)) } + unsafe { NonZero::new_unchecked(intrinsics::unchecked_add(self.step_minus_one, 1)) } } } @@ -231,12 +231,12 @@ unsafe impl StepByImpl for StepBy { #[inline] default fn spec_size_hint(&self) -> (usize, Option) { #[inline] - fn first_size(step: NonZeroUsize) -> impl Fn(usize) -> usize { + fn first_size(step: NonZero) -> impl Fn(usize) -> usize { move |n| if n == 0 { 0 } else { 1 + (n - 1) / step } } #[inline] - fn other_size(step: NonZeroUsize) -> impl Fn(usize) -> usize { + fn other_size(step: NonZero) -> impl Fn(usize) -> usize { move |n| n / step } diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index 955efb9b0f98d..e0c3b9f3b51da 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -1,7 +1,7 @@ use crate::ops::{Deref, DerefMut, DerefPure}; use crate::ptr; -/// A wrapper to inhibit compiler from automatically calling `T`’s destructor. +/// A wrapper to inhibit the compiler from automatically calling `T`’s destructor. /// This wrapper is 0-cost. /// /// `ManuallyDrop` is guaranteed to have the same layout and bit validity as diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 8a94964c8c5e6..8fe81a9f5289d 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -15,13 +15,204 @@ use crate::mem; /// Basic mathematical constants. #[unstable(feature = "f128", issue = "116909")] -pub mod consts {} +pub mod consts { + // FIXME: replace with mathematical constants from cmath. + + /// Archimedes' constant (π) + #[unstable(feature = "f128", issue = "116909")] + pub const PI: f128 = 3.14159265358979323846264338327950288419716939937510582097494_f128; + + /// The full circle constant (τ) + /// + /// Equal to 2π. + #[unstable(feature = "f128", issue = "116909")] + pub const TAU: f128 = 6.28318530717958647692528676655900576839433879875021164194989_f128; + + /// The golden ratio (φ) + #[unstable(feature = "f128", issue = "116909")] + // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + pub const PHI: f128 = 1.61803398874989484820458683436563811772030917980576286213545_f128; + + /// The Euler-Mascheroni constant (γ) + #[unstable(feature = "f128", issue = "116909")] + // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + pub const EGAMMA: f128 = 0.577215664901532860606512090082402431042159335939923598805767_f128; + + /// π/2 + #[unstable(feature = "f128", issue = "116909")] + pub const FRAC_PI_2: f128 = 1.57079632679489661923132169163975144209858469968755291048747_f128; + + /// π/3 + #[unstable(feature = "f128", issue = "116909")] + pub const FRAC_PI_3: f128 = 1.04719755119659774615421446109316762806572313312503527365831_f128; + + /// π/4 + #[unstable(feature = "f128", issue = "116909")] + pub const FRAC_PI_4: f128 = 0.785398163397448309615660845819875721049292349843776455243736_f128; + + /// π/6 + #[unstable(feature = "f128", issue = "116909")] + pub const FRAC_PI_6: f128 = 0.523598775598298873077107230546583814032861566562517636829157_f128; + + /// π/8 + #[unstable(feature = "f128", issue = "116909")] + pub const FRAC_PI_8: f128 = 0.392699081698724154807830422909937860524646174921888227621868_f128; + + /// 1/π + #[unstable(feature = "f128", issue = "116909")] + pub const FRAC_1_PI: f128 = 0.318309886183790671537767526745028724068919291480912897495335_f128; + + /// 1/sqrt(π) + #[unstable(feature = "f128", issue = "116909")] + // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + pub const FRAC_1_SQRT_PI: f128 = + 0.564189583547756286948079451560772585844050629328998856844086_f128; + + /// 2/π + #[unstable(feature = "f128", issue = "116909")] + pub const FRAC_2_PI: f128 = 0.636619772367581343075535053490057448137838582961825794990669_f128; + + /// 2/sqrt(π) + #[unstable(feature = "f128", issue = "116909")] + pub const FRAC_2_SQRT_PI: f128 = + 1.12837916709551257389615890312154517168810125865799771368817_f128; + + /// sqrt(2) + #[unstable(feature = "f128", issue = "116909")] + pub const SQRT_2: f128 = 1.41421356237309504880168872420969807856967187537694807317668_f128; + + /// 1/sqrt(2) + #[unstable(feature = "f128", issue = "116909")] + pub const FRAC_1_SQRT_2: f128 = + 0.707106781186547524400844362104849039284835937688474036588340_f128; + + /// sqrt(3) + #[unstable(feature = "f128", issue = "116909")] + // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + pub const SQRT_3: f128 = 1.73205080756887729352744634150587236694280525381038062805581_f128; + + /// 1/sqrt(3) + #[unstable(feature = "f128", issue = "116909")] + // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + pub const FRAC_1_SQRT_3: f128 = + 0.577350269189625764509148780501957455647601751270126876018602_f128; + + /// Euler's number (e) + #[unstable(feature = "f128", issue = "116909")] + pub const E: f128 = 2.71828182845904523536028747135266249775724709369995957496697_f128; + + /// log2(10) + #[unstable(feature = "f128", issue = "116909")] + pub const LOG2_10: f128 = 3.32192809488736234787031942948939017586483139302458061205476_f128; + + /// log2(e) + #[unstable(feature = "f128", issue = "116909")] + pub const LOG2_E: f128 = 1.44269504088896340735992468100189213742664595415298593413545_f128; + + /// log10(2) + #[unstable(feature = "f128", issue = "116909")] + pub const LOG10_2: f128 = 0.301029995663981195213738894724493026768189881462108541310427_f128; + + /// log10(e) + #[unstable(feature = "f128", issue = "116909")] + pub const LOG10_E: f128 = 0.434294481903251827651128918916605082294397005803666566114454_f128; + + /// ln(2) + #[unstable(feature = "f128", issue = "116909")] + pub const LN_2: f128 = 0.693147180559945309417232121458176568075500134360255254120680_f128; + + /// ln(10) + #[unstable(feature = "f128", issue = "116909")] + pub const LN_10: f128 = 2.30258509299404568401799145468436420760110148862877297603333_f128; +} #[cfg(not(test))] impl f128 { - // FIXME(f16_f128): almost everything in this `impl` is missing examples and a const + // FIXME(f16_f128): almost all methods in this `impl` are missing examples and a const // implementation. Add these once we can run code on all platforms and have f16/f128 in CTFE. + /// The radix or base of the internal representation of `f128`. + #[unstable(feature = "f128", issue = "116909")] + pub const RADIX: u32 = 2; + + /// Number of significant digits in base 2. + #[unstable(feature = "f128", issue = "116909")] + pub const MANTISSA_DIGITS: u32 = 113; + + /// Approximate number of significant digits in base 10. + /// + /// This is the maximum x such that any decimal number with x + /// significant digits can be converted to `f128` and back without loss. + /// + /// Equal to floor(log10 2[`MANTISSA_DIGITS`] − 1). + /// + /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS + #[unstable(feature = "f128", issue = "116909")] + pub const DIGITS: u32 = 33; + + /// [Machine epsilon] value for `f128`. + /// + /// This is the difference between `1.0` and the next larger representable number. + /// + /// Equal to 21 − [`MANTISSA_DIGITS`]. + /// + /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon + /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS + #[unstable(feature = "f128", issue = "116909")] + pub const EPSILON: f128 = 1.92592994438723585305597794258492731e-34_f128; + + /// Smallest finite `f128` value. + /// + /// Equal to −[`MAX`]. + /// + /// [`MAX`]: f128::MAX + #[unstable(feature = "f128", issue = "116909")] + pub const MIN: f128 = -1.18973149535723176508575932662800701e+4932_f128; + /// Smallest positive normal `f128` value. + /// + /// Equal to 2[`MIN_EXP`] − 1. + /// + /// [`MIN_EXP`]: f128::MIN_EXP + #[unstable(feature = "f128", issue = "116909")] + pub const MIN_POSITIVE: f128 = 3.36210314311209350626267781732175260e-4932_f128; + /// Largest finite `f128` value. + /// + /// Equal to + /// (1 − 2−[`MANTISSA_DIGITS`]) 2[`MAX_EXP`]. + /// + /// [`MANTISSA_DIGITS`]: f128::MANTISSA_DIGITS + /// [`MAX_EXP`]: f128::MAX_EXP + #[unstable(feature = "f128", issue = "116909")] + pub const MAX: f128 = 1.18973149535723176508575932662800701e+4932_f128; + + /// One greater than the minimum possible normal power of 2 exponent. + /// + /// If x = `MIN_EXP`, then normal numbers + /// ≥ 0.5 × 2x. + #[unstable(feature = "f128", issue = "116909")] + pub const MIN_EXP: i32 = -16_381; + /// Maximum possible power of 2 exponent. + /// + /// If x = `MAX_EXP`, then normal numbers + /// < 1 × 2x. + #[unstable(feature = "f128", issue = "116909")] + pub const MAX_EXP: i32 = 16_384; + + /// Minimum x for which 10x is normal. + /// + /// Equal to ceil(log10 [`MIN_POSITIVE`]). + /// + /// [`MIN_POSITIVE`]: f128::MIN_POSITIVE + #[unstable(feature = "f128", issue = "116909")] + pub const MIN_10_EXP: i32 = -4_931; + /// Maximum x for which 10x is normal. + /// + /// Equal to floor(log10 [`MAX`]). + /// + /// [`MAX`]: f128::MAX + #[unstable(feature = "f128", issue = "116909")] + pub const MAX_10_EXP: i32 = 4_932; + /// Returns `true` if this value is NaN. #[inline] #[must_use] diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 039f5188ba4a6..4290245ab2983 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -15,13 +15,200 @@ use crate::mem; /// Basic mathematical constants. #[unstable(feature = "f16", issue = "116909")] -pub mod consts {} +pub mod consts { + // FIXME: replace with mathematical constants from cmath. + + /// Archimedes' constant (π) + #[unstable(feature = "f16", issue = "116909")] + pub const PI: f16 = 3.14159265358979323846264338327950288_f16; + + /// The full circle constant (τ) + /// + /// Equal to 2π. + #[unstable(feature = "f16", issue = "116909")] + pub const TAU: f16 = 6.28318530717958647692528676655900577_f16; + + /// The golden ratio (φ) + #[unstable(feature = "f16", issue = "116909")] + // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + pub const PHI: f16 = 1.618033988749894848204586834365638118_f16; + + /// The Euler-Mascheroni constant (γ) + #[unstable(feature = "f16", issue = "116909")] + // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + pub const EGAMMA: f16 = 0.577215664901532860606512090082402431_f16; + + /// π/2 + #[unstable(feature = "f16", issue = "116909")] + pub const FRAC_PI_2: f16 = 1.57079632679489661923132169163975144_f16; + + /// π/3 + #[unstable(feature = "f16", issue = "116909")] + pub const FRAC_PI_3: f16 = 1.04719755119659774615421446109316763_f16; + + /// π/4 + #[unstable(feature = "f16", issue = "116909")] + pub const FRAC_PI_4: f16 = 0.785398163397448309615660845819875721_f16; + + /// π/6 + #[unstable(feature = "f16", issue = "116909")] + pub const FRAC_PI_6: f16 = 0.52359877559829887307710723054658381_f16; + + /// π/8 + #[unstable(feature = "f16", issue = "116909")] + pub const FRAC_PI_8: f16 = 0.39269908169872415480783042290993786_f16; + + /// 1/π + #[unstable(feature = "f16", issue = "116909")] + pub const FRAC_1_PI: f16 = 0.318309886183790671537767526745028724_f16; + + /// 1/sqrt(π) + #[unstable(feature = "f16", issue = "116909")] + // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + pub const FRAC_1_SQRT_PI: f16 = 0.564189583547756286948079451560772586_f16; + + /// 2/π + #[unstable(feature = "f16", issue = "116909")] + pub const FRAC_2_PI: f16 = 0.636619772367581343075535053490057448_f16; + + /// 2/sqrt(π) + #[unstable(feature = "f16", issue = "116909")] + pub const FRAC_2_SQRT_PI: f16 = 1.12837916709551257389615890312154517_f16; + + /// sqrt(2) + #[unstable(feature = "f16", issue = "116909")] + pub const SQRT_2: f16 = 1.41421356237309504880168872420969808_f16; + + /// 1/sqrt(2) + #[unstable(feature = "f16", issue = "116909")] + pub const FRAC_1_SQRT_2: f16 = 0.707106781186547524400844362104849039_f16; + + /// sqrt(3) + #[unstable(feature = "f16", issue = "116909")] + // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + pub const SQRT_3: f16 = 1.732050807568877293527446341505872367_f16; + + /// 1/sqrt(3) + #[unstable(feature = "f16", issue = "116909")] + // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + pub const FRAC_1_SQRT_3: f16 = 0.577350269189625764509148780501957456_f16; + + /// Euler's number (e) + #[unstable(feature = "f16", issue = "116909")] + pub const E: f16 = 2.71828182845904523536028747135266250_f16; + + /// log2(10) + #[unstable(feature = "f16", issue = "116909")] + pub const LOG2_10: f16 = 3.32192809488736234787031942948939018_f16; + + /// log2(e) + #[unstable(feature = "f16", issue = "116909")] + pub const LOG2_E: f16 = 1.44269504088896340735992468100189214_f16; + + /// log10(2) + #[unstable(feature = "f16", issue = "116909")] + pub const LOG10_2: f16 = 0.301029995663981195213738894724493027_f16; + + /// log10(e) + #[unstable(feature = "f16", issue = "116909")] + pub const LOG10_E: f16 = 0.434294481903251827651128918916605082_f16; + + /// ln(2) + #[unstable(feature = "f16", issue = "116909")] + pub const LN_2: f16 = 0.693147180559945309417232121458176568_f16; + + /// ln(10) + #[unstable(feature = "f16", issue = "116909")] + pub const LN_10: f16 = 2.30258509299404568401799145468436421_f16; +} #[cfg(not(test))] impl f16 { - // FIXME(f16_f128): almost everything in this `impl` is missing examples and a const + // FIXME(f16_f128): almost all methods in this `impl` are missing examples and a const // implementation. Add these once we can run code on all platforms and have f16/f128 in CTFE. + /// The radix or base of the internal representation of `f16`. + #[unstable(feature = "f16", issue = "116909")] + pub const RADIX: u32 = 2; + + /// Number of significant digits in base 2. + #[unstable(feature = "f16", issue = "116909")] + pub const MANTISSA_DIGITS: u32 = 11; + + /// Approximate number of significant digits in base 10. + /// + /// This is the maximum x such that any decimal number with x + /// significant digits can be converted to `f16` and back without loss. + /// + /// Equal to floor(log10 2[`MANTISSA_DIGITS`] − 1). + /// + /// [`MANTISSA_DIGITS`]: f16::MANTISSA_DIGITS + #[unstable(feature = "f16", issue = "116909")] + pub const DIGITS: u32 = 3; + + /// [Machine epsilon] value for `f16`. + /// + /// This is the difference between `1.0` and the next larger representable number. + /// + /// Equal to 21 − [`MANTISSA_DIGITS`]. + /// + /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon + /// [`MANTISSA_DIGITS`]: f16::MANTISSA_DIGITS + #[unstable(feature = "f16", issue = "116909")] + pub const EPSILON: f16 = 9.7656e-4_f16; + + /// Smallest finite `f16` value. + /// + /// Equal to −[`MAX`]. + /// + /// [`MAX`]: f16::MAX + #[unstable(feature = "f16", issue = "116909")] + pub const MIN: f16 = -6.5504e+4_f16; + /// Smallest positive normal `f16` value. + /// + /// Equal to 2[`MIN_EXP`] − 1. + /// + /// [`MIN_EXP`]: f16::MIN_EXP + #[unstable(feature = "f16", issue = "116909")] + pub const MIN_POSITIVE: f16 = 6.1035e-5_f16; + /// Largest finite `f16` value. + /// + /// Equal to + /// (1 − 2−[`MANTISSA_DIGITS`]) 2[`MAX_EXP`]. + /// + /// [`MANTISSA_DIGITS`]: f16::MANTISSA_DIGITS + /// [`MAX_EXP`]: f16::MAX_EXP + #[unstable(feature = "f16", issue = "116909")] + pub const MAX: f16 = 6.5504e+4_f16; + + /// One greater than the minimum possible normal power of 2 exponent. + /// + /// If x = `MIN_EXP`, then normal numbers + /// ≥ 0.5 × 2x. + #[unstable(feature = "f16", issue = "116909")] + pub const MIN_EXP: i32 = -13; + /// Maximum possible power of 2 exponent. + /// + /// If x = `MAX_EXP`, then normal numbers + /// < 1 × 2x. + #[unstable(feature = "f16", issue = "116909")] + pub const MAX_EXP: i32 = 16; + + /// Minimum x for which 10x is normal. + /// + /// Equal to ceil(log10 [`MIN_POSITIVE`]). + /// + /// [`MIN_POSITIVE`]: f16::MIN_POSITIVE + #[unstable(feature = "f16", issue = "116909")] + pub const MIN_10_EXP: i32 = -4; + /// Maximum x for which 10x is normal. + /// + /// Equal to floor(log10 [`MAX`]). + /// + /// [`MAX`]: f16::MAX + #[unstable(feature = "f16", issue = "116909")] + pub const MAX_10_EXP: i32 = 4; + /// Returns `true` if this value is NaN. #[inline] #[must_use] @@ -39,7 +226,7 @@ impl f16 { /// See [explanation of NaN as a special value](f32) for more info. #[inline] #[must_use] - #[unstable(feature = "f128", issue = "116909")] + #[unstable(feature = "f16", issue = "116909")] pub fn is_sign_positive(self) -> bool { !self.is_sign_negative() } @@ -52,7 +239,7 @@ impl f16 { /// See [explanation of NaN as a special value](f32) for more info. #[inline] #[must_use] - #[unstable(feature = "f128", issue = "116909")] + #[unstable(feature = "f16", 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. diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index c02f73fdf0364..09a341e4d80ac 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1412,11 +1412,9 @@ fn from_str_radix_panic_rt(radix: u32) -> ! { #[cfg_attr(feature = "panic_immediate_abort", inline)] #[cold] #[track_caller] -const fn from_str_radix_assert(radix: u32) { - if 2 > radix || radix > 36 { - // The only difference between these two functions is their panic message. - intrinsics::const_eval_select((radix,), from_str_radix_panic_ct, from_str_radix_panic_rt); - } +const fn from_str_radix_panic(radix: u32) { + // The only difference between these two functions is their panic message. + intrinsics::const_eval_select((radix,), from_str_radix_panic_ct, from_str_radix_panic_rt); } macro_rules! from_str_radix { @@ -1450,7 +1448,9 @@ macro_rules! from_str_radix { use self::IntErrorKind::*; use self::ParseIntError as PIE; - from_str_radix_assert(radix); + if 2 > radix || radix > 36 { + from_str_radix_panic(radix); + } if src.is_empty() { return Err(PIE { kind: Empty }); diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 5d3ae7316b124..fcdd983343d62 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -453,8 +453,7 @@ macro_rules! nonzero_integer { #[$stability:meta] Self = $Ty:ident, Primitive = $signedness:ident $Int:ident, - $(UnsignedNonZero = $UnsignedNonZero:ident,)? - UnsignedPrimitive = $UnsignedPrimitive:ty, + UnsignedPrimitive = $Uint:ty, // Used in doc comments. leading_zeros_test = $leading_zeros_test:expr, @@ -492,7 +491,7 @@ macro_rules! nonzero_integer { #[$stability] pub type $Ty = NonZero<$Int>; - impl $Ty { + impl NonZero<$Int> { /// The size of this non-zero integer type in bits. /// #[doc = concat!("This value is equal to [`", stringify!($Int), "::BITS`].")] @@ -500,9 +499,9 @@ macro_rules! nonzero_integer { /// # Examples /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - /// - #[doc = concat!("assert_eq!(", stringify!($Ty), "::BITS, ", stringify!($Int), "::BITS);")] + /// # use std::num::NonZero; + /// # + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::BITS, ", stringify!($Int), "::BITS);")] /// ``` #[stable(feature = "nonzero_bits", since = "1.67.0")] pub const BITS: u32 = <$Int>::BITS; @@ -516,7 +515,9 @@ macro_rules! nonzero_integer { /// Basic usage: /// /// ``` - #[doc = concat!("let n = std::num::", stringify!($Ty), "::new(", $leading_zeros_test, ").unwrap();")] + /// # use std::num::NonZero; + /// # + #[doc = concat!("let n = NonZero::<", stringify!($Int), ">::new(", $leading_zeros_test, ").unwrap();")] /// /// assert_eq!(n.leading_zeros(), 0); /// ``` @@ -528,7 +529,7 @@ macro_rules! nonzero_integer { pub const fn leading_zeros(self) -> u32 { // SAFETY: since `self` cannot be zero, it is safe to call `ctlz_nonzero`. unsafe { - intrinsics::ctlz_nonzero(self.get() as $UnsignedPrimitive) + intrinsics::ctlz_nonzero(self.get() as $Uint) } } @@ -542,7 +543,9 @@ macro_rules! nonzero_integer { /// Basic usage: /// /// ``` - #[doc = concat!("let n = std::num::", stringify!($Ty), "::new(0b0101000).unwrap();")] + /// # use std::num::NonZero; + /// # + #[doc = concat!("let n = NonZero::<", stringify!($Int), ">::new(0b0101000).unwrap();")] /// /// assert_eq!(n.trailing_zeros(), 3); /// ``` @@ -554,7 +557,7 @@ macro_rules! nonzero_integer { pub const fn trailing_zeros(self) -> u32 { // SAFETY: since `self` cannot be zero, it is safe to call `cttz_nonzero`. unsafe { - intrinsics::cttz_nonzero(self.get() as $UnsignedPrimitive) + intrinsics::cttz_nonzero(self.get() as $Uint) } } @@ -567,10 +570,10 @@ macro_rules! nonzero_integer { /// ``` /// #![feature(non_zero_count_ones)] /// + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - /// # use std::num::*; - /// # #[doc = concat!("let a = NonZero::<", stringify!($Int), ">::new(0b100_0000)?;")] #[doc = concat!("let b = NonZero::<", stringify!($Int), ">::new(0b100_0011)?;")] /// @@ -597,8 +600,7 @@ macro_rules! nonzero_integer { nonzero_integer_signedness_dependent_methods! { Self = $Ty, Primitive = $signedness $Int, - $(UnsignedNonZero = $UnsignedNonZero,)? - UnsignedPrimitive = $UnsignedPrimitive, + UnsignedPrimitive = $Uint, } /// Multiplies two non-zero integers together. @@ -608,13 +610,13 @@ macro_rules! nonzero_integer { /// # Examples /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] - #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] - #[doc = concat!("let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] + #[doc = concat!("let two = NonZero::new(2", stringify!($Int), ")?;")] + #[doc = concat!("let four = NonZero::new(4", stringify!($Int), ")?;")] + #[doc = concat!("let max = NonZero::new(", stringify!($Int), "::MAX)?;")] /// /// assert_eq!(Some(four), two.checked_mul(two)); /// assert_eq!(None, max.checked_mul(two)); @@ -642,18 +644,18 @@ macro_rules! nonzero_integer { } /// Multiplies two non-zero integers together. - #[doc = concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")] + #[doc = concat!("Return [`NonZero::<", stringify!($Int), ">::MAX`] on overflow.")] /// /// # Examples /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] - #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] - #[doc = concat!("let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] + #[doc = concat!("let two = NonZero::new(2", stringify!($Int), ")?;")] + #[doc = concat!("let four = NonZero::new(4", stringify!($Int), ")?;")] + #[doc = concat!("let max = NonZero::new(", stringify!($Int), "::MAX)?;")] /// /// assert_eq!(four, two.saturating_mul(two)); /// assert_eq!(max, four.saturating_mul(max)); @@ -698,11 +700,12 @@ macro_rules! nonzero_integer { /// ``` /// #![feature(nonzero_ops)] /// - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] - #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] + #[doc = concat!("let two = NonZero::new(2", stringify!($Int), ")?;")] + #[doc = concat!("let four = NonZero::new(4", stringify!($Int), ")?;")] /// /// assert_eq!(four, unsafe { two.unchecked_mul(two) }); /// # Some(()) @@ -724,13 +727,13 @@ macro_rules! nonzero_integer { /// # Examples /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")] - #[doc = concat!("let twenty_seven = ", stringify!($Ty), "::new(27)?;")] - #[doc = concat!("let half_max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX / 2)?;")] + #[doc = concat!("let three = NonZero::new(3", stringify!($Int), ")?;")] + #[doc = concat!("let twenty_seven = NonZero::new(27", stringify!($Int), ")?;")] + #[doc = concat!("let half_max = NonZero::new(", stringify!($Int), "::MAX / 2)?;")] /// /// assert_eq!(Some(twenty_seven), three.checked_pow(3)); /// assert_eq!(None, half_max.checked_pow(3)); @@ -761,24 +764,24 @@ macro_rules! nonzero_integer { #[doc = sign_dependent_expr!{ $signedness ? if signed { - concat!("Return [`", stringify!($Ty), "::MIN`] ", - "or [`", stringify!($Ty), "::MAX`] on overflow.") + concat!("Return [`NonZero::<", stringify!($Int), ">::MIN`] ", + "or [`NonZero::<", stringify!($Int), ">::MAX`] on overflow.") } if unsigned { - concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.") + concat!("Return [`NonZero::<", stringify!($Int), ">::MAX`] on overflow.") } }] /// /// # Examples /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")] - #[doc = concat!("let twenty_seven = ", stringify!($Ty), "::new(27)?;")] - #[doc = concat!("let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] + #[doc = concat!("let three = NonZero::new(3", stringify!($Int), ")?;")] + #[doc = concat!("let twenty_seven = NonZero::new(27", stringify!($Int), ")?;")] + #[doc = concat!("let max = NonZero::new(", stringify!($Int), "::MAX)?;")] /// /// assert_eq!(twenty_seven, three.saturating_pow(3)); /// assert_eq!(max, max.saturating_pow(3)); @@ -804,7 +807,7 @@ macro_rules! nonzero_integer { } #[stable(feature = "nonzero_parse", since = "1.35.0")] - impl FromStr for $Ty { + impl FromStr for NonZero<$Int> { type Err = ParseIntError; fn from_str(src: &str) -> Result { Self::new(<$Int>::from_str_radix(src, 10)?) @@ -842,56 +845,55 @@ macro_rules! nonzero_integer_signedness_dependent_impls { // Impls for unsigned nonzero types only. ($Ty:ident unsigned $Int:ty) => { #[stable(feature = "nonzero_div", since = "1.51.0")] - impl Div<$Ty> for $Int { + impl Div> for $Int { type Output = $Int; - /// This operation rounds towards zero, - /// truncating any fractional part of the exact result, and cannot panic. + /// This operation rounds towards zero, truncating any fractional + /// part of the exact result, and cannot panic. #[inline] - fn div(self, other: $Ty) -> $Int { - // SAFETY: div by zero is checked because `other` is a nonzero, + fn div(self, other: NonZero<$Int>) -> $Int { + // SAFETY: Division by zero is checked because `other` is non-zero, // and MIN/-1 is checked because `self` is an unsigned int. unsafe { intrinsics::unchecked_div(self, other.get()) } } } #[stable(feature = "nonzero_div_assign", since = "1.79.0")] - impl DivAssign<$Ty> for $Int { - /// This operation rounds towards zero, - /// truncating any fractional part of the exact result, and cannot panic. + impl DivAssign> for $Int { + /// This operation rounds towards zero, truncating any fractional + /// part of the exact result, and cannot panic. #[inline] - fn div_assign(&mut self, other: $Ty) { + fn div_assign(&mut self, other: NonZero<$Int>) { *self = *self / other; } } #[stable(feature = "nonzero_div", since = "1.51.0")] - impl Rem<$Ty> for $Int { + impl Rem> for $Int { type Output = $Int; /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic. #[inline] - fn rem(self, other: $Ty) -> $Int { - // SAFETY: rem by zero is checked because `other` is a nonzero, + fn rem(self, other: NonZero<$Int>) -> $Int { + // SAFETY: Remainder by zero is checked because `other` is non-zero, // and MIN/-1 is checked because `self` is an unsigned int. unsafe { intrinsics::unchecked_rem(self, other.get()) } } } #[stable(feature = "nonzero_div_assign", since = "1.79.0")] - impl RemAssign<$Ty> for $Int { + impl RemAssign> for $Int { /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic. #[inline] - fn rem_assign(&mut self, other: $Ty) { + fn rem_assign(&mut self, other: NonZero<$Int>) { *self = *self % other; } } }; - // Impls for signed nonzero types only. ($Ty:ident signed $Int:ty) => { #[stable(feature = "signed_nonzero_neg", since = "1.71.0")] - impl Neg for $Ty { + impl Neg for NonZero<$Int> { type Output = Self; #[inline] @@ -901,7 +903,7 @@ macro_rules! nonzero_integer_signedness_dependent_impls { } } - forward_ref_unop! { impl Neg, neg for $Ty, + forward_ref_unop! { impl Neg, neg for NonZero<$Int>, #[stable(feature = "signed_nonzero_neg", since = "1.71.0")] } }; } @@ -920,8 +922,9 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Examples /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), 1", stringify!($Int), ");")] + /// # use std::num::NonZero; + /// # + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::MIN.get(), 1", stringify!($Int), ");")] /// ``` #[stable(feature = "nonzero_min_max", since = "1.70.0")] pub const MIN: Self = Self::new(1).unwrap(); @@ -933,8 +936,9 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Examples /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")] + /// # use std::num::NonZero; + /// # + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::MAX.get(), ", stringify!($Int), "::MAX);")] /// ``` #[stable(feature = "nonzero_min_max", since = "1.70.0")] pub const MAX: Self = Self::new(<$Int>::MAX).unwrap(); @@ -947,13 +951,13 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Examples /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] - #[doc = concat!("let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] + #[doc = concat!("let one = NonZero::new(1", stringify!($Int), ")?;")] + #[doc = concat!("let two = NonZero::new(2", stringify!($Int), ")?;")] + #[doc = concat!("let max = NonZero::new(", stringify!($Int), "::MAX)?;")] /// /// assert_eq!(Some(two), one.checked_add(1)); /// assert_eq!(None, max.checked_add(1)); @@ -981,18 +985,18 @@ macro_rules! nonzero_integer_signedness_dependent_methods { } /// Adds an unsigned integer to a non-zero value. - #[doc = concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")] + #[doc = concat!("Return [`NonZero::<", stringify!($Int), ">::MAX`] on overflow.")] /// /// # Examples /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] - #[doc = concat!("let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] + #[doc = concat!("let one = NonZero::new(1", stringify!($Int), ")?;")] + #[doc = concat!("let two = NonZero::new(2", stringify!($Int), ")?;")] + #[doc = concat!("let max = NonZero::new(", stringify!($Int), "::MAX)?;")] /// /// assert_eq!(two, one.saturating_add(1)); /// assert_eq!(max, max.saturating_add(1)); @@ -1027,11 +1031,12 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// ``` /// #![feature(nonzero_ops)] /// - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let one = NonZero::new(1", stringify!($Int), ")?;")] + #[doc = concat!("let two = NonZero::new(2", stringify!($Int), ")?;")] /// /// assert_eq!(two, unsafe { one.unchecked_add(1) }); /// # Some(()) @@ -1054,14 +1059,14 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Examples /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] - #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")] - #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] - #[doc = concat!("let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] + #[doc = concat!("let two = NonZero::new(2", stringify!($Int), ")?;")] + #[doc = concat!("let three = NonZero::new(3", stringify!($Int), ")?;")] + #[doc = concat!("let four = NonZero::new(4", stringify!($Int), ")?;")] + #[doc = concat!("let max = NonZero::new(", stringify!($Int), "::MAX)?;")] /// /// assert_eq!(Some(two), two.checked_next_power_of_two() ); /// assert_eq!(Some(four), three.checked_next_power_of_two() ); @@ -1094,10 +1099,11 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Examples /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().ilog2(), 2);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")] + /// # use std::num::NonZero; + /// # + #[doc = concat!("assert_eq!(NonZero::new(7", stringify!($Int), ").unwrap().ilog2(), 2);")] + #[doc = concat!("assert_eq!(NonZero::new(8", stringify!($Int), ").unwrap().ilog2(), 3);")] + #[doc = concat!("assert_eq!(NonZero::new(9", stringify!($Int), ").unwrap().ilog2(), 3);")] /// ``` #[stable(feature = "int_log", since = "1.67.0")] #[rustc_const_stable(feature = "int_log", since = "1.67.0")] @@ -1118,10 +1124,11 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Examples /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().ilog10(), 1);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")] + /// # use std::num::NonZero; + /// # + #[doc = concat!("assert_eq!(NonZero::new(99", stringify!($Int), ").unwrap().ilog10(), 1);")] + #[doc = concat!("assert_eq!(NonZero::new(100", stringify!($Int), ").unwrap().ilog10(), 2);")] + #[doc = concat!("assert_eq!(NonZero::new(101", stringify!($Int), ").unwrap().ilog10(), 2);")] /// ``` #[stable(feature = "int_log", since = "1.67.0")] #[rustc_const_stable(feature = "int_log", since = "1.67.0")] @@ -1142,13 +1149,14 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// /// ``` /// #![feature(num_midpoint)] - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] - #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] + #[doc = concat!("let one = NonZero::new(1", stringify!($Int), ")?;")] + #[doc = concat!("let two = NonZero::new(2", stringify!($Int), ")?;")] + #[doc = concat!("let four = NonZero::new(4", stringify!($Int), ")?;")] /// /// assert_eq!(one.midpoint(four), two); /// assert_eq!(four.midpoint(one), two); @@ -1179,9 +1187,9 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// Basic usage: /// /// ``` - #[doc = concat!("let eight = std::num::", stringify!($Ty), "::new(8).unwrap();")] + #[doc = concat!("let eight = std::num::NonZero::new(8", stringify!($Int), ").unwrap();")] /// assert!(eight.is_power_of_two()); - #[doc = concat!("let ten = std::num::", stringify!($Ty), "::new(10).unwrap();")] + #[doc = concat!("let ten = std::num::NonZero::new(10", stringify!($Int), ").unwrap();")] /// assert!(!ten.is_power_of_two()); /// ``` #[must_use] @@ -1202,7 +1210,6 @@ macro_rules! nonzero_integer_signedness_dependent_methods { ( Self = $Ty:ident, Primitive = signed $Int:ident, - UnsignedNonZero = $Uty:ident, UnsignedPrimitive = $Uint:ty, ) => { /// The smallest value that can be represented by this non-zero @@ -1216,8 +1223,9 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Examples /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), ", stringify!($Int), "::MIN);")] + /// # use std::num::NonZero; + /// # + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::MIN.get(), ", stringify!($Int), "::MIN);")] /// ``` #[stable(feature = "nonzero_min_max", since = "1.70.0")] pub const MIN: Self = Self::new(<$Int>::MIN).unwrap(); @@ -1233,8 +1241,9 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Examples /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")] + /// # use std::num::NonZero; + /// # + #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::MAX.get(), ", stringify!($Int), "::MAX);")] /// ``` #[stable(feature = "nonzero_min_max", since = "1.70.0")] pub const MAX: Self = Self::new(<$Int>::MAX).unwrap(); @@ -1246,11 +1255,12 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Example /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] + #[doc = concat!("let pos = NonZero::new(1", stringify!($Int), ")?;")] + #[doc = concat!("let neg = NonZero::new(-1", stringify!($Int), ")?;")] /// /// assert_eq!(pos, pos.abs()); /// assert_eq!(pos, neg.abs()); @@ -1269,19 +1279,19 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// Checked absolute value. /// Checks for overflow and returns [`None`] if - #[doc = concat!("`self == ", stringify!($Ty), "::MIN`.")] + #[doc = concat!("`self == NonZero::<", stringify!($Int), ">::MIN`.")] /// The result cannot be zero. /// /// # Example /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] - #[doc = concat!("let min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] + #[doc = concat!("let pos = NonZero::new(1", stringify!($Int), ")?;")] + #[doc = concat!("let neg = NonZero::new(-1", stringify!($Int), ")?;")] + #[doc = concat!("let min = NonZero::new(", stringify!($Int), "::MIN)?;")] /// /// assert_eq!(Some(pos), neg.checked_abs()); /// assert_eq!(None, min.checked_abs()); @@ -1309,13 +1319,13 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Example /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] - #[doc = concat!("let min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] + #[doc = concat!("let pos = NonZero::new(1", stringify!($Int), ")?;")] + #[doc = concat!("let neg = NonZero::new(-1", stringify!($Int), ")?;")] + #[doc = concat!("let min = NonZero::new(", stringify!($Int), "::MIN)?;")] /// /// assert_eq!((pos, false), pos.overflowing_abs()); /// assert_eq!((pos, false), neg.overflowing_abs()); @@ -1343,17 +1353,15 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Example /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] - #[doc = concat!("let min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] - #[doc = concat!("let min_plus = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN + 1)?;")] - #[doc = concat!("let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] + #[doc = concat!("let pos = NonZero::new(1", stringify!($Int), ")?;")] + #[doc = concat!("let neg = NonZero::new(-1", stringify!($Int), ")?;")] + #[doc = concat!("let min = NonZero::new(", stringify!($Int), "::MIN)?;")] + #[doc = concat!("let min_plus = NonZero::new(", stringify!($Int), "::MIN + 1)?;")] + #[doc = concat!("let max = NonZero::new(", stringify!($Int), "::MAX)?;")] /// /// assert_eq!(pos, pos.saturating_abs()); /// assert_eq!(pos, neg.saturating_abs()); @@ -1378,15 +1386,14 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Example /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")] - #[doc = concat!("let min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] - #[doc = concat!("# let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] + #[doc = concat!("let pos = NonZero::new(1", stringify!($Int), ")?;")] + #[doc = concat!("let neg = NonZero::new(-1", stringify!($Int), ")?;")] + #[doc = concat!("let min = NonZero::new(", stringify!($Int), "::MIN)?;")] + #[doc = concat!("# let max = NonZero::new(", stringify!($Int), "::MAX)?;")] /// /// assert_eq!(pos, pos.wrapping_abs()); /// assert_eq!(pos, neg.wrapping_abs()); @@ -1411,18 +1418,15 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Example /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] - #[doc = concat!("# use std::num::", stringify!($Uty), ";")] - /// + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let u_pos = ", stringify!($Uty), "::new(1)?;")] - #[doc = concat!("let i_pos = ", stringify!($Ty), "::new(1)?;")] - #[doc = concat!("let i_neg = ", stringify!($Ty), "::new(-1)?;")] - #[doc = concat!("let i_min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] - #[doc = concat!("let u_max = ", stringify!($Uty), "::new(", - stringify!($Uint), "::MAX / 2 + 1)?;")] + #[doc = concat!("let u_pos = NonZero::new(1", stringify!($Uint), ")?;")] + #[doc = concat!("let i_pos = NonZero::new(1", stringify!($Int), ")?;")] + #[doc = concat!("let i_neg = NonZero::new(-1", stringify!($Int), ")?;")] + #[doc = concat!("let i_min = NonZero::new(", stringify!($Int), "::MIN)?;")] + #[doc = concat!("let u_max = NonZero::new(", stringify!($Uint), "::MAX / 2 + 1)?;")] /// /// assert_eq!(u_pos, i_pos.unsigned_abs()); /// assert_eq!(u_pos, i_neg.unsigned_abs()); @@ -1435,9 +1439,9 @@ macro_rules! nonzero_integer_signedness_dependent_methods { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn unsigned_abs(self) -> $Uty { + pub const fn unsigned_abs(self) -> NonZero<$Uint> { // SAFETY: absolute value of nonzero cannot yield zero values. - unsafe { $Uty::new_unchecked(self.get().unsigned_abs()) } + unsafe { NonZero::new_unchecked(self.get().unsigned_abs()) } } /// Returns `true` if `self` is positive and `false` if the @@ -1446,11 +1450,12 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Example /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] - #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] + #[doc = concat!("let pos_five = NonZero::new(5", stringify!($Int), ")?;")] + #[doc = concat!("let neg_five = NonZero::new(-5", stringify!($Int), ")?;")] /// /// assert!(pos_five.is_positive()); /// assert!(!neg_five.is_positive()); @@ -1471,11 +1476,12 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Example /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] - #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] + #[doc = concat!("let pos_five = NonZero::new(5", stringify!($Int), ")?;")] + #[doc = concat!("let neg_five = NonZero::new(-5", stringify!($Int), ")?;")] /// /// assert!(neg_five.is_negative()); /// assert!(!pos_five.is_negative()); @@ -1491,18 +1497,18 @@ macro_rules! nonzero_integer_signedness_dependent_methods { } /// Checked negation. Computes `-self`, - #[doc = concat!("returning `None` if `self == ", stringify!($Ty), "::MIN`.")] + #[doc = concat!("returning `None` if `self == NonZero::<", stringify!($Int), ">::MIN`.")] /// /// # Example /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] - #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] - #[doc = concat!("let min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] + #[doc = concat!("let pos_five = NonZero::new(5", stringify!($Int), ")?;")] + #[doc = concat!("let neg_five = NonZero::new(-5", stringify!($Int), ")?;")] + #[doc = concat!("let min = NonZero::new(", stringify!($Int), "::MIN)?;")] /// /// assert_eq!(pos_five.checked_neg(), Some(neg_five)); /// assert_eq!(min.checked_neg(), None); @@ -1528,13 +1534,13 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Example /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] - #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] - #[doc = concat!("let min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] + #[doc = concat!("let pos_five = NonZero::new(5", stringify!($Int), ")?;")] + #[doc = concat!("let neg_five = NonZero::new(-5", stringify!($Int), ")?;")] + #[doc = concat!("let min = NonZero::new(", stringify!($Int), "::MIN)?;")] /// /// assert_eq!(pos_five.overflowing_neg(), (neg_five, false)); /// assert_eq!(min.overflowing_neg(), (min, true)); @@ -1551,24 +1557,22 @@ macro_rules! nonzero_integer_signedness_dependent_methods { } /// Saturating negation. Computes `-self`, - #[doc = concat!("returning [`", stringify!($Ty), "::MAX`]")] - #[doc = concat!("if `self == ", stringify!($Ty), "::MIN`")] + #[doc = concat!("returning [`NonZero::<", stringify!($Int), ">::MAX`]")] + #[doc = concat!("if `self == NonZero::<", stringify!($Int), ">::MIN`")] /// instead of overflowing. /// /// # Example /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] - #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] - #[doc = concat!("let min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] - #[doc = concat!("let min_plus_one = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN + 1)?;")] - #[doc = concat!("let max = ", stringify!($Ty), "::new(", - stringify!($Int), "::MAX)?;")] + #[doc = concat!("let pos_five = NonZero::new(5", stringify!($Int), ")?;")] + #[doc = concat!("let neg_five = NonZero::new(-5", stringify!($Int), ")?;")] + #[doc = concat!("let min = NonZero::new(", stringify!($Int), "::MIN)?;")] + #[doc = concat!("let min_plus_one = NonZero::new(", stringify!($Int), "::MIN + 1)?;")] + #[doc = concat!("let max = NonZero::new(", stringify!($Int), "::MAX)?;")] /// /// assert_eq!(pos_five.saturating_neg(), neg_five); /// assert_eq!(min.saturating_neg(), max); @@ -1595,13 +1599,13 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// # Example /// /// ``` - #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// # use std::num::NonZero; + /// # /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { - #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")] - #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")] - #[doc = concat!("let min = ", stringify!($Ty), "::new(", - stringify!($Int), "::MIN)?;")] + #[doc = concat!("let pos_five = NonZero::new(5", stringify!($Int), ")?;")] + #[doc = concat!("let neg_five = NonZero::new(-5", stringify!($Int), ")?;")] + #[doc = concat!("let min = NonZero::new(", stringify!($Int), "::MIN)?;")] /// /// assert_eq!(pos_five.wrapping_neg(), neg_five); /// assert_eq!(min.wrapping_neg(), min); @@ -1662,41 +1666,35 @@ nonzero_integer! { nonzero_integer! { Self = NonZeroI8, Primitive = signed i8, - UnsignedNonZero = NonZeroU8, UnsignedPrimitive = u8, } nonzero_integer! { Self = NonZeroI16, Primitive = signed i16, - UnsignedNonZero = NonZeroU16, UnsignedPrimitive = u16, } nonzero_integer! { Self = NonZeroI32, Primitive = signed i32, - UnsignedNonZero = NonZeroU32, UnsignedPrimitive = u32, } nonzero_integer! { Self = NonZeroI64, Primitive = signed i64, - UnsignedNonZero = NonZeroU64, UnsignedPrimitive = u64, } nonzero_integer! { Self = NonZeroI128, Primitive = signed i128, - UnsignedNonZero = NonZeroU128, UnsignedPrimitive = u128, } nonzero_integer! { Self = NonZeroIsize, Primitive = signed isize, - UnsignedNonZero = NonZeroUsize, UnsignedPrimitive = usize, } diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 673144cb32827..48a96c5792c64 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2764,6 +2764,7 @@ macro_rules! uint_impl { /// ``` #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2);")] #[doc = concat!("assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".next_power_of_two(), 1);")] /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index d8597369b9bfd..8283fdc459be1 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1467,8 +1467,9 @@ mod prim_usize {} /// For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, when such values cross an API /// boundary, the following invariants must generally be upheld: /// +/// * `t` is non-null /// * `t` is aligned to `align_of_val(t)` -/// * `t` is dereferenceable for `size_of_val(t)` many bytes +/// * if `size_of_val(t) > 0`, then `t` is dereferenceable for `size_of_val(t)` many bytes /// /// If `t` points at address `a`, being "dereferenceable" for N bytes means that the memory range /// `[a, a + N)` is all contained within a single [allocated object]. diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 5f3815859c8fa..8d7192c1b0fd1 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -812,7 +812,7 @@ pub const fn from_mut(r: &mut T) -> *mut T { #[rustc_allow_const_fn_unstable(ptr_metadata)] #[rustc_diagnostic_item = "ptr_slice_from_raw_parts"] pub const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { - from_raw_parts(data.cast(), len) + intrinsics::aggregate_raw_ptr(data, len) } /// Forms a raw mutable slice from a pointer and a length. @@ -858,7 +858,7 @@ pub const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { #[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")] #[rustc_diagnostic_item = "ptr_slice_from_raw_parts_mut"] pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { - from_raw_parts_mut(data.cast(), len) + intrinsics::aggregate_raw_ptr(data, len) } /// Swaps the values at two mutable locations of the same type, without diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 5c4f0bf9b2b49..8ad045275adec 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -114,18 +114,17 @@ impl [u8] { /// Returns a byte slice with leading ASCII whitespace bytes removed. /// /// 'Whitespace' refers to the definition used by - /// `u8::is_ascii_whitespace`. + /// [`u8::is_ascii_whitespace`]. /// /// # Examples /// /// ``` - /// #![feature(byte_slice_trim_ascii)] - /// /// assert_eq!(b" \t hello world\n".trim_ascii_start(), b"hello world\n"); /// assert_eq!(b" ".trim_ascii_start(), b""); /// assert_eq!(b"".trim_ascii_start(), b""); /// ``` - #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")] + #[stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn trim_ascii_start(&self) -> &[u8] { let mut bytes = self; @@ -144,18 +143,17 @@ impl [u8] { /// Returns a byte slice with trailing ASCII whitespace bytes removed. /// /// 'Whitespace' refers to the definition used by - /// `u8::is_ascii_whitespace`. + /// [`u8::is_ascii_whitespace`]. /// /// # Examples /// /// ``` - /// #![feature(byte_slice_trim_ascii)] - /// /// assert_eq!(b"\r hello world\n ".trim_ascii_end(), b"\r hello world"); /// assert_eq!(b" ".trim_ascii_end(), b""); /// assert_eq!(b"".trim_ascii_end(), b""); /// ``` - #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")] + #[stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn trim_ascii_end(&self) -> &[u8] { let mut bytes = self; @@ -175,18 +173,17 @@ impl [u8] { /// removed. /// /// 'Whitespace' refers to the definition used by - /// `u8::is_ascii_whitespace`. + /// [`u8::is_ascii_whitespace`]. /// /// # Examples /// /// ``` - /// #![feature(byte_slice_trim_ascii)] - /// /// assert_eq!(b"\r hello world\n ".trim_ascii(), b"hello world"); /// assert_eq!(b" ".trim_ascii(), b""); /// assert_eq!(b"".trim_ascii(), b""); /// ``` - #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")] + #[stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn trim_ascii(&self) -> &[u8] { self.trim_ascii_start().trim_ascii_end() diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index ed7bcec89b9f9..9bee50424b3d6 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -544,7 +544,7 @@ impl [T] { /// ``` #[inline] #[stable(feature = "slice_first_last_chunk", since = "1.77.0")] - #[rustc_const_unstable(feature = "const_slice_first_last_chunk", issue = "111774")] + #[rustc_const_stable(feature = "slice_first_last_chunk", since = "1.77.0")] pub const fn last_chunk(&self) -> Option<&[T; N]> { if self.len() < N { None @@ -1337,8 +1337,10 @@ impl [T] { #[must_use] pub const fn as_chunks(&self) -> (&[[T; N]], &[T]) { assert!(N != 0, "chunk size must be non-zero"); - let len = self.len() / N; - let (multiple_of_n, remainder) = self.split_at(len * N); + let len_rounded_down = self.len() / N * N; + // SAFETY: The rounded-down value is always the same or smaller than the + // original length, and thus must be in-bounds of the slice. + let (multiple_of_n, remainder) = unsafe { self.split_at_unchecked(len_rounded_down) }; // SAFETY: We already panicked for zero, and ensured by construction // that the length of the subslice is a multiple of N. let array_slice = unsafe { multiple_of_n.as_chunks_unchecked() }; @@ -1487,8 +1489,10 @@ impl [T] { #[must_use] pub const fn as_chunks_mut(&mut self) -> (&mut [[T; N]], &mut [T]) { assert!(N != 0, "chunk size must be non-zero"); - let len = self.len() / N; - let (multiple_of_n, remainder) = self.split_at_mut(len * N); + let len_rounded_down = self.len() / N * N; + // SAFETY: The rounded-down value is always the same or smaller than the + // original length, and thus must be in-bounds of the slice. + let (multiple_of_n, remainder) = unsafe { self.split_at_mut_unchecked(len_rounded_down) }; // SAFETY: We already panicked for zero, and ensured by construction // that the length of the subslice is a multiple of N. let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_mut() }; diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index b6f65907d3c30..669cdc92e3586 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -2531,15 +2531,14 @@ impl str { /// # Examples /// /// ``` - /// #![feature(byte_slice_trim_ascii)] - /// /// assert_eq!(" \t \u{3000}hello world\n".trim_ascii_start(), "\u{3000}hello world\n"); /// assert_eq!(" ".trim_ascii_start(), ""); /// assert_eq!("".trim_ascii_start(), ""); /// ``` - #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")] #[must_use = "this returns the trimmed string as a new slice, \ without modifying the original"] + #[stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn trim_ascii_start(&self) -> &str { // SAFETY: Removing ASCII characters from a `&str` does not invalidate @@ -2557,15 +2556,14 @@ impl str { /// # Examples /// /// ``` - /// #![feature(byte_slice_trim_ascii)] - /// /// assert_eq!("\r hello world\u{3000}\n ".trim_ascii_end(), "\r hello world\u{3000}"); /// assert_eq!(" ".trim_ascii_end(), ""); /// assert_eq!("".trim_ascii_end(), ""); /// ``` - #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")] #[must_use = "this returns the trimmed string as a new slice, \ without modifying the original"] + #[stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn trim_ascii_end(&self) -> &str { // SAFETY: Removing ASCII characters from a `&str` does not invalidate @@ -2584,15 +2582,14 @@ impl str { /// # Examples /// /// ``` - /// #![feature(byte_slice_trim_ascii)] - /// /// assert_eq!("\r hello world\n ".trim_ascii(), "hello world"); /// assert_eq!(" ".trim_ascii(), ""); /// assert_eq!("".trim_ascii(), ""); /// ``` - #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")] #[must_use = "this returns the trimmed string as a new slice, \ without modifying the original"] + #[stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn trim_ascii(&self) -> &str { // SAFETY: Removing ASCII characters from a `&str` does not invalidate diff --git a/library/profiler_builtins/Cargo.toml b/library/profiler_builtins/Cargo.toml index 937149f8e86d6..5b10fb5a2bd3f 100644 --- a/library/profiler_builtins/Cargo.toml +++ b/library/profiler_builtins/Cargo.toml @@ -13,4 +13,4 @@ core = { path = "../core" } compiler_builtins = { version = "0.1.0", features = ['rustc-dep-of-std'] } [build-dependencies] -cc = "1.0.90" +cc = "1.0.97" diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 52729ba1f8456..1720fe84fa7c1 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -31,10 +31,11 @@ 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 } +libc = { version = "=0.2.153", default-features = false, features = ['rustc-dep-of-std'], public = true } +# Pin libc (pending https://github.com/rust-lang/rust/pull/124560) [target.'cfg(all(windows, target_env = "msvc"))'.dependencies] -libc = { version = "0.2.153", default-features = false } +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/src/fs.rs b/library/std/src/fs.rs index 409ead0e28433..77e94365b08ec 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -408,6 +408,9 @@ impl File { /// /// This function will create a file if it does not exist, or return an error if it does. This /// way, if the call succeeds, the file returned is guaranteed to be new. + /// If a file exists at the target location, creating a new file will fail with [`AlreadyExists`] + /// or another error based on the situation. See [`OpenOptions::open`] for a + /// non-exhaustive list of likely errors. /// /// This option is useful because it is atomic. Otherwise between checking whether a file /// exists and creating a new one, the file may have been created by another process (a TOCTOU @@ -416,6 +419,8 @@ impl File { /// This can also be written using /// `File::options().read(true).write(true).create_new(true).open(...)`. /// + /// [`AlreadyExists`]: crate::io::ErrorKind::AlreadyExists + /// /// # Examples /// /// ```no_run @@ -1071,6 +1076,9 @@ impl OpenOptions { /// /// No file is allowed to exist at the target location, also no (dangling) symlink. In this /// way, if the call succeeds, the file returned is guaranteed to be new. + /// If a file exists at the target location, creating a new file will fail with [`AlreadyExists`] + /// or another error based on the situation. See [`OpenOptions::open`] for a + /// non-exhaustive list of likely errors. /// /// This option is useful because it is atomic. Otherwise between checking /// whether a file exists and creating a new one, the file may have been @@ -1084,6 +1092,7 @@ impl OpenOptions { /// /// [`.create()`]: OpenOptions::create /// [`.truncate()`]: OpenOptions::truncate + /// [`AlreadyExists`]: io::ErrorKind::AlreadyExists /// /// # Examples /// @@ -2258,7 +2267,7 @@ pub fn canonicalize>(path: P) -> io::Result { /// # Platform-specific behavior /// /// This function currently corresponds to the `mkdir` function on Unix -/// and the `CreateDirectory` function on Windows. +/// and the `CreateDirectoryW` function on Windows. /// Note that, this [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior @@ -2298,10 +2307,14 @@ pub fn create_dir>(path: P) -> io::Result<()> { /// Recursively create a directory and all of its parent components if they /// are missing. /// +/// If this function returns an error, some of the parent components might have +/// been created already. +/// /// # Platform-specific behavior /// -/// This function currently corresponds to the `mkdir` function on Unix -/// and the `CreateDirectory` function on Windows. +/// This function currently corresponds to multiple calls to the `mkdir` +/// function on Unix and the `CreateDirectoryW` function on Windows. +/// /// Note that, this [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index af055152cbe7f..5c6e7b7bd50f0 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -1839,7 +1839,11 @@ pub trait Write { if output.error.is_err() { output.error } else { - Err(error::const_io_error!(ErrorKind::Uncategorized, "formatter error")) + // This shouldn't happen: the underlying stream did not error, but somehow + // the formatter still errored? + panic!( + "a formatting trait implementation returned an error when the underlying stream did not" + ); } } } diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 7e53acbc3878a..a55199c82fc10 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -81,21 +81,25 @@ impl UnixListener { ))] const backlog: core::ffi::c_int = 128; #[cfg(any( + // Silently capped to `/proc/sys/net/core/somaxconn`. target_os = "linux", + // Silently capped to `kern.ipc.soacceptqueue`. target_os = "freebsd", + // Silently capped to `kern.somaxconn sysctl`. target_os = "openbsd", - target_os = "macos" + // Silently capped to the default 128. + target_vendor = "apple", ))] const backlog: core::ffi::c_int = -1; #[cfg(not(any( target_os = "windows", target_os = "redox", + target_os = "espidf", + target_os = "horizon", target_os = "linux", target_os = "freebsd", target_os = "openbsd", - target_os = "macos", - target_os = "espidf", - target_os = "horizon" + target_vendor = "apple", )))] const backlog: libc::c_int = libc::SOMAXCONN; diff --git a/library/std/src/sys/pal/unix/alloc.rs b/library/std/src/sys/pal/unix/alloc.rs index af0089978ecbb..993bf55edcf10 100644 --- a/library/std/src/sys/pal/unix/alloc.rs +++ b/library/std/src/sys/pal/unix/alloc.rs @@ -13,7 +13,13 @@ unsafe impl GlobalAlloc for System { if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { libc::malloc(layout.size()) as *mut u8 } else { - #[cfg(target_os = "macos")] + // `posix_memalign` returns a non-aligned value if supplied a very + // large alignment on older versions of Apple's platforms (unknown + // exactly which version range, but the issue is definitely + // present in macOS 10.14 and iOS 13.3). + // + // + #[cfg(target_vendor = "apple")] { if layout.align() > (1 << 31) { return ptr::null_mut(); @@ -55,9 +61,7 @@ unsafe impl GlobalAlloc for System { cfg_if::cfg_if! { if #[cfg(any( target_os = "android", - target_os = "illumos", target_os = "redox", - target_os = "solaris", target_os = "espidf", target_os = "horizon", target_os = "vita", diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs index 203c7180001f5..1701717db597c 100644 --- a/library/std/src/sys/pal/unix/fd.rs +++ b/library/std/src/sys/pal/unix/fd.rs @@ -33,14 +33,15 @@ pub struct FileDesc(OwnedFd); // with the man page quoting that if the count of bytes to read is // greater than `SSIZE_MAX` the result is "unspecified". // -// On macOS, however, apparently the 64-bit libc is either buggy or +// On Apple targets however, apparently the 64-bit libc is either buggy or // intentionally showing odd behavior by rejecting any read with a size // larger than or equal to INT_MAX. To handle both of these the read // size is capped on both platforms. -#[cfg(target_os = "macos")] -const READ_LIMIT: usize = libc::c_int::MAX as usize - 1; -#[cfg(not(target_os = "macos"))] -const READ_LIMIT: usize = libc::ssize_t::MAX as usize; +const READ_LIMIT: usize = if cfg!(target_vendor = "apple") { + libc::c_int::MAX as usize - 1 +} else { + libc::ssize_t::MAX as usize +}; #[cfg(any( target_os = "dragonfly", diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 32cdd13fbebda..fbbd40bfb796a 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -1493,11 +1493,11 @@ impl fmt::Debug for File { readlink(&p).ok() } - #[cfg(target_os = "macos")] + #[cfg(target_vendor = "apple")] fn get_path(fd: c_int) -> Option { // FIXME: The use of PATH_MAX is generally not encouraged, but it - // is inevitable in this case because macOS defines `fcntl` with - // `F_GETPATH` in terms of `MAXPATHLEN`, and there are no + // is inevitable in this case because Apple targets define `fcntl` + // with `F_GETPATH` in terms of `MAXPATHLEN`, and there are no // alternatives. If a better method is invented, it should be used // instead. let mut buf = vec![0; libc::PATH_MAX as usize]; @@ -1538,12 +1538,12 @@ impl fmt::Debug for File { #[cfg(not(any( target_os = "linux", - target_os = "macos", target_os = "vxworks", all(target_os = "freebsd", target_arch = "x86_64"), target_os = "netbsd", target_os = "illumos", - target_os = "solaris" + target_os = "solaris", + target_vendor = "apple", )))] fn get_path(_fd: c_int) -> Option { // FIXME(#24570): implement this for other Unix platforms @@ -1552,12 +1552,12 @@ impl fmt::Debug for File { #[cfg(any( target_os = "linux", - target_os = "macos", target_os = "freebsd", target_os = "hurd", target_os = "netbsd", target_os = "openbsd", - target_os = "vxworks" + target_os = "vxworks", + target_vendor = "apple", ))] fn get_mode(fd: c_int) -> Option<(bool, bool)> { let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; @@ -1574,12 +1574,12 @@ impl fmt::Debug for File { #[cfg(not(any( target_os = "linux", - target_os = "macos", target_os = "freebsd", target_os = "hurd", target_os = "netbsd", target_os = "openbsd", - target_os = "vxworks" + target_os = "vxworks", + target_vendor = "apple", )))] fn get_mode(_fd: c_int) -> Option<(bool, bool)> { // FIXME(#24570): implement this for other Unix platforms diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index 1ac5729c02fd4..21f233e22620c 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -63,11 +63,11 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { args::init(argc, argv); // Normally, `thread::spawn` will call `Thread::set_name` but since this thread - // already exists, we have to call it ourselves. We only do this on macos + // already exists, we have to call it ourselves. We only do this on Apple targets // because some unix-like operating systems such as Linux share process-id and // thread-id for the main thread and so renaming the main thread will rename the // process and we only want to enable this on platforms we've tested. - if cfg!(target_os = "macos") { + if cfg!(target_vendor = "apple") { thread::Thread::set_name(&c"main"); } diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs index 7237989c9059b..b8dc1538a6378 100644 --- a/library/std/src/sys/pal/unix/net.rs +++ b/library/std/src/sys/pal/unix/net.rs @@ -86,7 +86,14 @@ impl Socket { // flag to atomically create the socket and set it as // CLOEXEC. On Linux this was added in 2.6.27. let fd = cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0))?; - Ok(Socket(FileDesc::from_raw_fd(fd))) + let socket = Socket(FileDesc::from_raw_fd(fd)); + + // DragonFlyBSD, FreeBSD and NetBSD use `SO_NOSIGPIPE` as a `setsockopt` + // flag to disable `SIGPIPE` emission on socket. + #[cfg(any(target_os = "freebsd", target_os = "netbsd", target_os = "dragonfly"))] + setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?; + + Ok(socket) } else { let fd = cvt(libc::socket(fam, ty, 0))?; let fd = FileDesc::from_raw_fd(fd); diff --git a/library/std/src/sys/pal/unix/rand.rs b/library/std/src/sys/pal/unix/rand.rs index d8f227b4ef444..e6df109a6b8f2 100644 --- a/library/std/src/sys/pal/unix/rand.rs +++ b/library/std/src/sys/pal/unix/rand.rs @@ -59,7 +59,14 @@ mod imp { unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_NONBLOCK) } } - #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "freebsd", netbsd10))] + #[cfg(any( + target_os = "espidf", + target_os = "horizon", + target_os = "freebsd", + netbsd10, + target_os = "illumos", + target_os = "solaris" + ))] fn getrandom(buf: &mut [u8]) -> libc::ssize_t { unsafe { libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) } } @@ -83,6 +90,8 @@ mod imp { target_os = "horizon", target_os = "freebsd", target_os = "dragonfly", + target_os = "solaris", + target_os = "illumos", netbsd10 )))] fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool { @@ -96,6 +105,8 @@ mod imp { target_os = "horizon", target_os = "freebsd", target_os = "dragonfly", + target_os = "solaris", + target_os = "illumos", netbsd10 ))] fn getrandom_fill_bytes(v: &mut [u8]) -> bool { diff --git a/tests/ui/stdlib-unit-tests/builtin-clone.rs b/library/std/tests/builtin-clone.rs similarity index 69% rename from tests/ui/stdlib-unit-tests/builtin-clone.rs rename to library/std/tests/builtin-clone.rs index 47c00ede0e971..66b57130c954b 100644 --- a/tests/ui/stdlib-unit-tests/builtin-clone.rs +++ b/library/std/tests/builtin-clone.rs @@ -1,4 +1,3 @@ -//@ run-pass // Test that `Clone` is correctly implemented for builtin types. // Also test that cloning an array or a tuple is done right, i.e. // each component is cloned. @@ -7,7 +6,7 @@ fn test_clone(arg: T) { let _ = arg.clone(); } -fn foo() { } +fn foo() {} #[derive(Debug, PartialEq, Eq)] struct S(i32); @@ -18,7 +17,8 @@ impl Clone for S { } } -fn main() { +#[test] +fn builtin_clone() { test_clone(foo); test_clone([1; 56]); test_clone((1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)); @@ -27,19 +27,7 @@ fn main() { let b = [S(1), S(2), S(3)]; assert_eq!(b, a.clone()); - let a = ( - (S(1), S(0)), - ( - (S(0), S(0), S(1)), - S(0) - ) - ); - let b = ( - (S(2), S(1)), - ( - (S(1), S(1), S(2)), - S(1) - ) - ); + let a = ((S(1), S(0)), ((S(0), S(0), S(1)), S(0))); + let b = ((S(2), S(1)), ((S(1), S(1), S(2)), S(1))); assert_eq!(b, a.clone()); } diff --git a/library/std/tests/eq-multidispatch.rs b/library/std/tests/eq-multidispatch.rs new file mode 100644 index 0000000000000..96e440f85e0ac --- /dev/null +++ b/library/std/tests/eq-multidispatch.rs @@ -0,0 +1,51 @@ +#[derive(PartialEq, Debug)] +struct Bar; +#[derive(Debug)] +struct Baz; +#[derive(Debug)] +struct Foo; +#[derive(Debug)] +struct Fu; + +impl PartialEq for Baz { + fn eq(&self, _: &Baz) -> bool { + true + } +} + +impl PartialEq for Foo { + fn eq(&self, _: &Fu) -> bool { + true + } +} + +impl PartialEq for Fu { + fn eq(&self, _: &Foo) -> bool { + true + } +} + +impl PartialEq for Foo { + fn eq(&self, _: &Bar) -> bool { + false + } +} + +impl PartialEq for Bar { + fn eq(&self, _: &Foo) -> bool { + false + } +} + +#[test] +fn eq_multidispatch() { + assert!(Bar != Foo); + assert!(Foo != Bar); + + assert_eq!(Bar, Bar); + + assert_eq!(Baz, Baz); + + assert_eq!(Foo, Fu); + assert_eq!(Fu, Foo); +} diff --git a/tests/ui/stdlib-unit-tests/istr.rs b/library/std/tests/istr.rs similarity index 82% rename from tests/ui/stdlib-unit-tests/istr.rs rename to library/std/tests/istr.rs index f6298919425d1..9a127ae803e77 100644 --- a/tests/ui/stdlib-unit-tests/istr.rs +++ b/library/std/tests/istr.rs @@ -1,5 +1,4 @@ -//@ run-pass - +#[test] fn test_stack_assign() { let s: String = "a".to_string(); println!("{}", s.clone()); @@ -9,8 +8,12 @@ fn test_stack_assign() { assert!((s != u)); } -fn test_heap_lit() { "a big string".to_string(); } +#[test] +fn test_heap_lit() { + "a big string".to_string(); +} +#[test] fn test_heap_assign() { let s: String = "a big ol' string".to_string(); let t: String = "a big ol' string".to_string(); @@ -19,11 +22,13 @@ fn test_heap_assign() { assert!((s != u)); } +#[test] fn test_heap_log() { let s = "a big ol' string".to_string(); println!("{}", s); } +#[test] fn test_append() { let mut s = String::new(); s.push_str("a"); @@ -41,11 +46,3 @@ fn test_append() { s.push_str("&tea"); assert_eq!(s, "coffee&tea"); } - -pub fn main() { - test_stack_assign(); - test_heap_lit(); - test_heap_assign(); - test_heap_log(); - test_append(); -} diff --git a/tests/ui/stdlib-unit-tests/log-knows-the-names-of-variants-in-std.rs b/library/std/tests/log-knows-the-names-of-variants-in-std.rs similarity index 85% rename from tests/ui/stdlib-unit-tests/log-knows-the-names-of-variants-in-std.rs rename to library/std/tests/log-knows-the-names-of-variants-in-std.rs index 8f351b2b40b6f..118bee620185c 100644 --- a/tests/ui/stdlib-unit-tests/log-knows-the-names-of-variants-in-std.rs +++ b/library/std/tests/log-knows-the-names-of-variants-in-std.rs @@ -1,18 +1,18 @@ -//@ run-pass - #![allow(non_camel_case_types)] #![allow(dead_code)] + #[derive(Clone, Debug)] enum foo { - a(usize), - b(String), + a(usize), + b(String), } fn check_log(exp: String, v: T) { assert_eq!(exp, format!("{:?}", v)); } -pub fn main() { +#[test] +fn log_knows_the_names_of_variants_in_std() { let mut x = Some(foo::a(22)); let exp = "Some(a(22))".to_string(); let act = format!("{:?}", x); diff --git a/tests/ui/stdlib-unit-tests/minmax-stability-issue-23687.rs b/library/std/tests/minmax-stability-issue-23687.rs similarity index 96% rename from tests/ui/stdlib-unit-tests/minmax-stability-issue-23687.rs rename to library/std/tests/minmax-stability-issue-23687.rs index bf42347df0bf4..119c520de8f05 100644 --- a/tests/ui/stdlib-unit-tests/minmax-stability-issue-23687.rs +++ b/library/std/tests/minmax-stability-issue-23687.rs @@ -1,12 +1,10 @@ -//@ run-pass - -use std::fmt::Debug; use std::cmp::{self, Ordering}; +use std::fmt::Debug; #[derive(Debug, Copy, Clone, PartialEq, Eq)] struct Foo { n: u8, - name: &'static str + name: &'static str, } impl PartialOrd for Foo { @@ -21,7 +19,8 @@ impl Ord for Foo { } } -fn main() { +#[test] +fn minmax_stability() { let a = Foo { n: 4, name: "a" }; let b = Foo { n: 4, name: "b" }; let c = Foo { n: 8, name: "c" }; diff --git a/tests/ui/stdlib-unit-tests/seq-compare.rs b/library/std/tests/seq-compare.rs similarity index 95% rename from tests/ui/stdlib-unit-tests/seq-compare.rs rename to library/std/tests/seq-compare.rs index 1be0569e17c09..221f1c7cabde5 100644 --- a/tests/ui/stdlib-unit-tests/seq-compare.rs +++ b/library/std/tests/seq-compare.rs @@ -1,6 +1,5 @@ -//@ run-pass - -pub fn main() { +#[test] +fn seq_compare() { assert!(("hello".to_string() < "hellr".to_string())); assert!(("hello ".to_string() > "hello".to_string())); assert!(("hello".to_string() != "there".to_string())); diff --git a/tests/ui/std/slice-from-array-issue-113238.rs b/library/std/tests/slice-from-array-issue-113238.rs similarity index 90% rename from tests/ui/std/slice-from-array-issue-113238.rs rename to library/std/tests/slice-from-array-issue-113238.rs index 44f2d7a9478b6..97aba4fec01e0 100644 --- a/tests/ui/std/slice-from-array-issue-113238.rs +++ b/library/std/tests/slice-from-array-issue-113238.rs @@ -1,9 +1,8 @@ -//@ check-pass - // This intends to use the unsizing coercion from array to slice, but it only // works if we resolve `<&[u8]>::from` as the reflexive `From for T`. In // #113238, we found that gimli had added its own `From for &[u8]` // that affected all `std/backtrace` users. -fn main() { +#[test] +fn slice_from_array() { let _ = <&[u8]>::from(&[]); } diff --git a/tests/ui/stdlib-unit-tests/issue-21058.rs b/library/std/tests/type-name-unsized.rs similarity index 63% rename from tests/ui/stdlib-unit-tests/issue-21058.rs rename to library/std/tests/type-name-unsized.rs index 0e04f1e21b8b3..2974668b2ce71 100644 --- a/tests/ui/stdlib-unit-tests/issue-21058.rs +++ b/library/std/tests/type-name-unsized.rs @@ -1,10 +1,13 @@ -//@ run-pass #![allow(dead_code)] use std::fmt::Debug; struct NT(str); -struct DST { a: u32, b: str } + +struct DST { + a: u32, + b: str, +} macro_rules! check { (val: $ty_of:expr, $expected:expr) => { @@ -15,23 +18,24 @@ macro_rules! check { }; } -fn main() { - // type_name should support unsized types +/// Tests that [`std::any::type_name`] supports unsized types. +#[test] +fn type_name_unsized() { check!([u8], "[u8]"); check!(str, "str"); check!(dyn Send, "dyn core::marker::Send"); - check!(NT, "issue_21058::NT"); - check!(DST, "issue_21058::DST"); + check!(NT, "type_name_unsized::NT"); + check!(DST, "type_name_unsized::DST"); check!(&i32, "&i32"); check!(&'static i32, "&i32"); check!((i32, u32), "(i32, u32)"); - check!(val: foo(), "issue_21058::Foo"); - check!(val: Foo::new, "issue_21058::Foo::new"); + check!(val: foo(), "type_name_unsized::Foo"); + check!(val: Foo::new, "type_name_unsized::Foo::new"); check!(val: ::fmt, - "::fmt" + "::fmt" ); - check!(val: || {}, "issue_21058::main::{{closure}}"); + check!(val: || {}, "type_name_unsized::type_name_unsized::{{closure}}"); bar::(); } @@ -56,7 +60,9 @@ fn type_name_of_val(_: T) -> &'static str { struct Foo; impl Foo { - fn new() -> Self { Foo } + fn new() -> Self { + Foo + } } fn foo() -> impl Debug { diff --git a/tests/ui/stdlib-unit-tests/volatile-fat-ptr.rs b/library/std/tests/volatile-fat-ptr.rs similarity index 90% rename from tests/ui/stdlib-unit-tests/volatile-fat-ptr.rs rename to library/std/tests/volatile-fat-ptr.rs index ef227a9134dd6..b005c12c6187b 100644 --- a/tests/ui/stdlib-unit-tests/volatile-fat-ptr.rs +++ b/library/std/tests/volatile-fat-ptr.rs @@ -1,10 +1,10 @@ -//@ run-pass - #![allow(stable_features)] #![feature(volatile)] + use std::ptr::{read_volatile, write_volatile}; -fn main() { +#[test] +fn volatile_fat_ptr() { let mut x: &'static str = "test"; unsafe { let a = read_volatile(&x); diff --git a/library/test/src/bench.rs b/library/test/src/bench.rs index 23925e6ea72ec..9a5dc351f6d07 100644 --- a/library/test/src/bench.rs +++ b/library/test/src/bench.rs @@ -68,12 +68,12 @@ pub fn fmt_bench_samples(bs: &BenchSamples) -> String { use std::fmt::Write; let mut output = String::new(); - let median = bs.ns_iter_summ.median as usize; - let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize; + let median = bs.ns_iter_summ.median; + let deviation = bs.ns_iter_summ.max - bs.ns_iter_summ.min; write!( output, - "{:>11} ns/iter (+/- {})", + "{:>14} ns/iter (+/- {})", fmt_thousands_sep(median, ','), fmt_thousands_sep(deviation, ',') ) @@ -85,24 +85,27 @@ pub fn fmt_bench_samples(bs: &BenchSamples) -> String { } // Format a number with thousands separators -fn fmt_thousands_sep(mut n: usize, sep: char) -> String { +fn fmt_thousands_sep(mut n: f64, sep: char) -> String { use std::fmt::Write; let mut output = String::new(); let mut trailing = false; for &pow in &[9, 6, 3, 0] { let base = 10_usize.pow(pow); - if pow == 0 || trailing || n / base != 0 { - if !trailing { - write!(output, "{}", n / base).unwrap(); - } else { - write!(output, "{:03}", n / base).unwrap(); + if pow == 0 || trailing || n / base as f64 >= 1.0 { + match (pow, trailing) { + // modern CPUs can execute multiple instructions per nanosecond + // e.g. benching an ADD takes about 0.25ns. + (0, true) => write!(output, "{:06.2}", n / base as f64).unwrap(), + (0, false) => write!(output, "{:.2}", n / base as f64).unwrap(), + (_, true) => write!(output, "{:03}", n as usize / base).unwrap(), + _ => write!(output, "{}", n as usize / base).unwrap() } if pow != 0 { output.push(sep); } trailing = true; } - n %= base; + n %= base as f64; } output diff --git a/library/test/src/formatters/json.rs b/library/test/src/formatters/json.rs index 47c4e7757e40c..6245aae17c4d7 100644 --- a/library/test/src/formatters/json.rs +++ b/library/test/src/formatters/json.rs @@ -167,8 +167,8 @@ impl OutputFormatter for JsonFormatter { ), TestResult::TrBench(ref bs) => { - let median = bs.ns_iter_summ.median as usize; - let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize; + let median = bs.ns_iter_summ.median; + let deviation = bs.ns_iter_summ.max - bs.ns_iter_summ.min; let mbps = if bs.mb_s == 0 { String::new() diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 9c2b7500a20f7..4a5d768961ff9 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -98,9 +98,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.73" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" [[package]] name = "cfg-if" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index e9675e204523f..ca0d1fa5bd0c0 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -36,7 +36,7 @@ test = false # Most of the time updating these dependencies requires modifications to the # bootstrap codebase(e.g., https://github.com/rust-lang/rust/issues/124565); # otherwise, some targets will fail. That's why these dependencies are explicitly pinned. -cc = "=1.0.73" +cc = "=1.0.97" cmake = "=0.1.48" build_helper = { path = "../tools/build_helper" } diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index e464e444fea20..e60e8f0aa1f70 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -3,7 +3,6 @@ import contextlib import datetime import hashlib -import json import os import re import shutil @@ -52,7 +51,7 @@ def get(base, url, path, checksums, verbose=False): try: if url not in checksums: - raise RuntimeError(("src/stage0.json doesn't contain a checksum for {}. " + raise RuntimeError(("src/stage0 doesn't contain a checksum for {}. " "Pre-built artifacts might not be available for this " "target at this time, see https://doc.rust-lang.org/nightly" "/rustc/platform-support.html for more information.") @@ -421,9 +420,9 @@ def output(filepath): class Stage0Toolchain: - def __init__(self, stage0_payload): - self.date = stage0_payload["date"] - self.version = stage0_payload["version"] + def __init__(self, date, version): + self.date = date + self.version = version def channel(self): return self.version + "-" + self.date @@ -439,7 +438,7 @@ def __init__( bin_root, tarball_path, tarball_suffix, - checksums_sha256, + stage0_data, pattern, verbose, ): @@ -448,7 +447,7 @@ def __init__( self.bin_root = bin_root self.tarball_path = tarball_path self.tarball_suffix = tarball_suffix - self.checksums_sha256 = checksums_sha256 + self.stage0_data = stage0_data self.pattern = pattern self.verbose = verbose @@ -458,7 +457,7 @@ def download_component(download_info): download_info.base_download_url, download_info.download_path, download_info.tarball_path, - download_info.checksums_sha256, + download_info.stage0_data, verbose=download_info.verbose, ) @@ -510,11 +509,12 @@ def __init__(self, config_toml="", args=None): build_dir = args.build_dir or self.get_toml('build-dir', 'build') or 'build' self.build_dir = os.path.abspath(build_dir) - with open(os.path.join(self.rust_root, "src", "stage0.json")) as f: - data = json.load(f) - self.checksums_sha256 = data["checksums_sha256"] - self.stage0_compiler = Stage0Toolchain(data["compiler"]) - self.download_url = os.getenv("RUSTUP_DIST_SERVER") or data["config"]["dist_server"] + self.stage0_data = parse_stage0_file(os.path.join(self.rust_root, "src", "stage0")) + self.stage0_compiler = Stage0Toolchain( + self.stage0_data["compiler_date"], + self.stage0_data["compiler_version"] + ) + self.download_url = os.getenv("RUSTUP_DIST_SERVER") or self.stage0_data["dist_server"] self.build = args.build or self.build_triple() @@ -581,7 +581,7 @@ def download_toolchain(self): bin_root=self.bin_root(), tarball_path=os.path.join(rustc_cache, filename), tarball_suffix=tarball_suffix, - checksums_sha256=self.checksums_sha256, + stage0_data=self.stage0_data, pattern=pattern, verbose=self.verbose, ) @@ -1071,6 +1071,16 @@ def parse_args(args): return parser.parse_known_args(args)[0] +def parse_stage0_file(path): + result = {} + with open(path, 'r') as file: + for line in file: + line = line.strip() + if line and not line.startswith('#'): + key, value = line.split('=', 1) + result[key.strip()] = value.strip() + return result + def bootstrap(args): """Configure, fetch, build and run the initial bootstrap""" rust_root = os.path.abspath(os.path.join(__file__, '../../..')) diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index 4b182a7a693dd..d227419917767 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -91,12 +91,13 @@ fn main() { rustc_real }; - let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER_REAL") { - let mut cmd = Command::new(wrapper); - cmd.arg(rustc_driver); - cmd - } else { - Command::new(rustc_driver) + let mut cmd = match env::var_os("RUSTC_WRAPPER_REAL") { + Some(wrapper) if !wrapper.is_empty() => { + let mut cmd = Command::new(wrapper); + cmd.arg(rustc_driver); + cmd + } + _ => Command::new(rustc_driver), }; cmd.args(&args).env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index d4473e240399f..3af1a05caa829 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -20,7 +20,9 @@ use std::sync::OnceLock; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::core::config::{Config, TargetSelection}; use crate::utils::channel; -use crate::utils::helpers::{self, exe, get_clang_cl_resource_dir, output, t, up_to_date}; +use crate::utils::helpers::{ + self, exe, get_clang_cl_resource_dir, output, t, unhashed_basename, up_to_date, +}; use crate::{generate_smart_stamp_hash, CLang, GitRepo, Kind}; use build_helper::ci::CiEnv; @@ -506,7 +508,7 @@ impl Step for Llvm { cfg.define("LLVM_VERSION_SUFFIX", suffix); } - configure_cmake(builder, target, &mut cfg, true, ldflags, &[]); + configure_cmake(builder, target, &mut cfg, true, ldflags, &[], &[]); configure_llvm(builder, target, &mut cfg); for (key, val) in &builder.config.llvm_build_config { @@ -596,6 +598,7 @@ fn configure_cmake( use_compiler_launcher: bool, mut ldflags: LdFlags, extra_compiler_flags: &[&str], + suppressed_compiler_flag_prefixes: &[&str], ) { // Do not print installation messages for up-to-date files. // LLVM and LLD builds can produce a lot of those and hit CI limits on log size. @@ -729,7 +732,17 @@ fn configure_cmake( } cfg.build_arg("-j").build_arg(builder.jobs().to_string()); - let mut cflags: OsString = builder.cflags(target, GitRepo::Llvm, CLang::C).join(" ").into(); + let mut cflags: OsString = builder + .cflags(target, GitRepo::Llvm, CLang::C) + .into_iter() + .filter(|flag| { + !suppressed_compiler_flag_prefixes + .iter() + .any(|suppressed_prefix| flag.starts_with(suppressed_prefix)) + }) + .collect::>() + .join(" ") + .into(); if let Some(ref s) = builder.config.llvm_cflags { cflags.push(" "); cflags.push(s); @@ -742,7 +755,17 @@ fn configure_cmake( cflags.push(&format!(" {flag}")); } cfg.define("CMAKE_C_FLAGS", cflags); - let mut cxxflags: OsString = builder.cflags(target, GitRepo::Llvm, CLang::Cxx).join(" ").into(); + let mut cxxflags: OsString = builder + .cflags(target, GitRepo::Llvm, CLang::Cxx) + .into_iter() + .filter(|flag| { + !suppressed_compiler_flag_prefixes + .iter() + .any(|suppressed_prefix| flag.starts_with(suppressed_prefix)) + }) + .collect::>() + .join(" ") + .into(); if let Some(ref s) = builder.config.llvm_cxxflags { cxxflags.push(" "); cxxflags.push(s); @@ -921,7 +944,7 @@ impl Step for Lld { ldflags.push_all("-Wl,-rpath,'$ORIGIN/../../../'"); } - configure_cmake(builder, target, &mut cfg, true, ldflags, &[]); + configure_cmake(builder, target, &mut cfg, true, ldflags, &[], &[]); configure_llvm(builder, target, &mut cfg); // Re-use the same flags as llvm to control the level of debug information @@ -1022,6 +1045,12 @@ impl Step for Sanitizers { let use_compiler_launcher = !self.target.contains("apple-darwin"); let extra_compiler_flags: &[&str] = if self.target.contains("apple") { &["-fembed-bitcode=off"] } else { &[] }; + // Since v1.0.86, the cc crate adds -mmacosx-version-min to the default + // flags on MacOS. A long-standing bug in the CMake rules for compiler-rt + // causes architecture detection to be skipped when this flag is present, + // and compilation fails. https://github.com/llvm/llvm-project/issues/88780 + let suppressed_compiler_flag_prefixes: &[&str] = + if self.target.contains("apple-darwin") { &["-mmacosx-version-min="] } else { &[] }; configure_cmake( builder, self.target, @@ -1029,6 +1058,7 @@ impl Step for Sanitizers { use_compiler_launcher, LdFlags::default(), extra_compiler_flags, + suppressed_compiler_flag_prefixes, ); t!(fs::create_dir_all(&out_dir)); @@ -1190,7 +1220,7 @@ impl Step for CrtBeginEnd { let crtbegin_src = builder.src.join("src/llvm-project/compiler-rt/lib/builtins/crtbegin.c"); let crtend_src = builder.src.join("src/llvm-project/compiler-rt/lib/builtins/crtend.c"); - if up_to_date(&crtbegin_src, &out_dir.join("crtbegin.o")) + if up_to_date(&crtbegin_src, &out_dir.join("crtbeginS.o")) && up_to_date(&crtend_src, &out_dir.join("crtendS.o")) { return out_dir; @@ -1222,10 +1252,15 @@ impl Step for CrtBeginEnd { .define("CRT_HAS_INITFINI_ARRAY", None) .define("EH_USE_FRAME_REGISTRY", None); - cfg.compile("crt"); + let objs = cfg.compile_intermediates(); + assert_eq!(objs.len(), 2); + for obj in objs { + let base_name = unhashed_basename(&obj); + assert!(base_name == "crtbegin" || base_name == "crtend"); + t!(fs::copy(&obj, out_dir.join(format!("{}S.o", base_name)))); + t!(fs::rename(&obj, out_dir.join(format!("{}.o", base_name)))); + } - t!(fs::copy(out_dir.join("crtbegin.o"), out_dir.join("crtbeginS.o"))); - t!(fs::copy(out_dir.join("crtend.o"), out_dir.join("crtendS.o"))); out_dir } } @@ -1372,9 +1407,9 @@ impl Step for Libunwind { for entry in fs::read_dir(&out_dir).unwrap() { let file = entry.unwrap().path().canonicalize().unwrap(); if file.is_file() && file.extension() == Some(OsStr::new("o")) { - // file name starts with "Unwind-EHABI", "Unwind-seh" or "libunwind" - let file_name = file.file_name().unwrap().to_str().expect("UTF-8 file name"); - if cpp_sources.iter().any(|f| file_name.starts_with(&f[..f.len() - 4])) { + // Object file name without the hash prefix is "Unwind-EHABI", "Unwind-seh" or "libunwind". + let base_name = unhashed_basename(&file); + if cpp_sources.iter().any(|f| *base_name == f[..f.len() - 4]) { cc_cfg.object(&file); count += 1; } diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 6c4b26ec2195f..045cde56f4119 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -88,6 +88,9 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash { /// Primary function to execute this rule. Can call `builder.ensure()` /// with other steps to run those. + /// + /// This gets called twice during a normal `./x.py` execution: first + /// with `dry_run() == true`, and then for real. fn run(self, builder: &Builder<'_>) -> Self::Output; /// When bootstrap is passed a set of paths, this controls whether this rule @@ -317,11 +320,13 @@ const PATH_REMAP: &[(&str, &[&str])] = &[ ( "tests", &[ + // tidy-alphabetical-start "tests/assembly", "tests/codegen", "tests/codegen-units", "tests/coverage", "tests/coverage-run-rustdoc", + "tests/crashes", "tests/debuginfo", "tests/incremental", "tests/mir-opt", @@ -337,6 +342,7 @@ const PATH_REMAP: &[(&str, &[&str])] = &[ "tests/rustdoc-ui", "tests/ui", "tests/ui-fulldeps", + // tidy-alphabetical-end ], ), ]; @@ -2549,7 +2555,12 @@ impl Cargo { // FIXME: the guard against msvc shouldn't need to be here if target.is_msvc() { if let Some(ref cl) = builder.config.llvm_clang_cl { - self.command.env("CC", cl).env("CXX", cl); + // FIXME: There is a bug in Clang 18 when building for ARM64: + // https://github.com/llvm/llvm-project/pull/81849. This is + // fixed in LLVM 19, but can't be backported. + if !target.starts_with("aarch64") && !target.starts_with("arm64ec") { + self.command.env("CC", cl).env("CXX", cl); + } } } else { let ccache = builder.config.ccache.as_ref(); diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index caec46366dde0..9710365ef114d 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -32,7 +32,7 @@ fn configure_with_args(cmd: &[String], host: &[&str], target: &[&str]) -> Config .join(&thread::current().name().unwrap_or("unknown").replace(":", "-")); t!(fs::create_dir_all(&dir)); config.out = dir; - config.build = TargetSelection::from_user("A"); + config.build = TargetSelection::from_user("A-A"); config.hosts = host.iter().map(|s| TargetSelection::from_user(s)).collect(); config.targets = target.iter().map(|s| TargetSelection::from_user(s)).collect(); config @@ -53,27 +53,27 @@ fn run_build(paths: &[PathBuf], config: Config) -> Cache { fn check_cli(paths: [&str; N]) { run_build( &paths.map(PathBuf::from), - configure_with_args(&paths.map(String::from), &["A"], &["A"]), + configure_with_args(&paths.map(String::from), &["A-A"], &["A-A"]), ); } macro_rules! std { ($host:ident => $target:ident, stage = $stage:literal) => { compile::Std::new( - Compiler { host: TargetSelection::from_user(stringify!($host)), stage: $stage }, - TargetSelection::from_user(stringify!($target)), + Compiler { host: TargetSelection::from_user(concat!(stringify!($host), "-", stringify!($host))), stage: $stage }, + TargetSelection::from_user(concat!(stringify!($target), "-", stringify!($target))), ) }; } macro_rules! doc_std { ($host:ident => $target:ident, stage = $stage:literal) => {{ - let config = configure("doc", &["A"], &["A"]); + let config = configure("doc", &["A-A"], &["A-A"]); let build = Build::new(config); let builder = Builder::new(&build); doc::Std::new( $stage, - TargetSelection::from_user(stringify!($target)), + TargetSelection::from_user(concat!(stringify!($target), "-", stringify!($target))), &builder, DocumentationFormat::Html, ) @@ -83,8 +83,8 @@ macro_rules! doc_std { macro_rules! rustc { ($host:ident => $target:ident, stage = $stage:literal) => { compile::Rustc::new( - Compiler { host: TargetSelection::from_user(stringify!($host)), stage: $stage }, - TargetSelection::from_user(stringify!($target)), + Compiler { host: TargetSelection::from_user(concat!(stringify!($host), "-", stringify!($host))), stage: $stage }, + TargetSelection::from_user(concat!(stringify!($target), "-", stringify!($target))), ) }; } @@ -117,7 +117,7 @@ fn test_intersection() { #[test] fn validate_path_remap() { - let build = Build::new(configure("test", &["A"], &["A"])); + let build = Build::new(configure("test", &["A-A"], &["A-A"])); PATH_REMAP .iter() @@ -128,9 +128,29 @@ fn validate_path_remap() { }); } +#[test] +fn check_missing_paths_for_x_test_tests() { + let build = Build::new(configure("test", &["A-A"], &["A-A"])); + + let (_, tests_remap_paths) = + PATH_REMAP.iter().find(|(target_path, _)| *target_path == "tests").unwrap(); + + let tests_dir = fs::read_dir(build.src.join("tests")).unwrap(); + for dir in tests_dir { + let path = dir.unwrap().path(); + + // Skip if not a test directory. + if path.ends_with("tests/auxiliary") || !path.is_dir() { + continue + } + + assert!(tests_remap_paths.iter().any(|item| path.ends_with(*item)), "{} is missing in PATH_REMAP tests list.", path.display()); + } +} + #[test] fn test_exclude() { - let mut config = configure("test", &["A"], &["A"]); + let mut config = configure("test", &["A-A"], &["A-A"]); config.skip = vec!["src/tools/tidy".into()]; let cache = run_build(&[], config); @@ -145,7 +165,7 @@ fn test_exclude() { fn test_exclude_kind() { let path = PathBuf::from("compiler/rustc_data_structures"); - let mut config = configure("test", &["A"], &["A"]); + let mut config = configure("test", &["A-A"], &["A-A"]); // Ensure our test is valid, and `test::Rustc` would be run without the exclude. assert!(run_build(&[], config.clone()).contains::()); // Ensure tests for rustc are not skipped. @@ -159,13 +179,13 @@ fn test_exclude_kind() { #[test] fn alias_and_path_for_library() { let mut cache = - run_build(&["library".into(), "core".into()], configure("build", &["A"], &["A"])); + run_build(&["library".into(), "core".into()], configure("build", &["A-A"], &["A-A"])); assert_eq!( first(cache.all::()), &[std!(A => A, stage = 0), std!(A => A, stage = 1)] ); - let mut cache = run_build(&["library".into(), "core".into()], configure("doc", &["A"], &["A"])); + let mut cache = run_build(&["library".into(), "core".into()], configure("doc", &["A-A"], &["A-A"])); assert_eq!(first(cache.all::()), &[doc_std!(A => A, stage = 0)]); } @@ -177,9 +197,9 @@ mod defaults { #[test] fn build_default() { - let mut cache = run_build(&[], configure("build", &["A"], &["A"])); + let mut cache = run_build(&[], configure("build", &["A-A"], &["A-A"])); - let a = TargetSelection::from_user("A"); + let a = TargetSelection::from_user("A-A"); assert_eq!( first(cache.all::()), &[std!(A => A, stage = 0), std!(A => A, stage = 1),] @@ -197,10 +217,10 @@ mod defaults { #[test] fn build_stage_0() { - let config = Config { stage: 0, ..configure("build", &["A"], &["A"]) }; + let config = Config { stage: 0, ..configure("build", &["A-A"], &["A-A"]) }; let mut cache = run_build(&[], config); - let a = TargetSelection::from_user("A"); + let a = TargetSelection::from_user("A-A"); assert_eq!(first(cache.all::()), &[std!(A => A, stage = 0)]); assert!(!cache.all::().is_empty()); assert_eq!( @@ -214,11 +234,11 @@ mod defaults { #[test] fn build_cross_compile() { - let config = Config { stage: 1, ..configure("build", &["A", "B"], &["A", "B"]) }; + let config = Config { stage: 1, ..configure("build", &["A-A", "B-B"], &["A-A", "B-B"]) }; let mut cache = run_build(&[], config); - let a = TargetSelection::from_user("A"); - let b = TargetSelection::from_user("B"); + let a = TargetSelection::from_user("A-A"); + let b = TargetSelection::from_user("B-B"); // Ideally, this build wouldn't actually have `target: a` // rustdoc/rustcc/std here (the user only requested a host=B build, so @@ -257,11 +277,11 @@ mod defaults { #[test] fn doc_default() { - let mut config = configure("doc", &["A"], &["A"]); + let mut config = configure("doc", &["A-A"], &["A-A"]); config.compiler_docs = true; config.cmd = Subcommand::Doc { open: false, json: false }; let mut cache = run_build(&[], config); - let a = TargetSelection::from_user("A"); + let a = TargetSelection::from_user("A-A"); // error_index_generator uses stage 0 to share rustdoc artifacts with the // rustdoc tool. @@ -291,9 +311,9 @@ mod dist { #[test] fn dist_baseline() { - let mut cache = run_build(&[], configure(&["A"], &["A"])); + let mut cache = run_build(&[], configure(&["A-A"], &["A-A"])); - let a = TargetSelection::from_user("A"); + let a = TargetSelection::from_user("A-A"); assert_eq!(first(cache.all::()), &[dist::Docs { host: a },]); assert_eq!(first(cache.all::()), &[dist::Mingw { host: a },]); @@ -315,10 +335,10 @@ mod dist { #[test] fn dist_with_targets() { - let mut cache = run_build(&[], configure(&["A"], &["A", "B"])); + let mut cache = run_build(&[], configure(&["A-A"], &["A-A", "B-B"])); - let a = TargetSelection::from_user("A"); - let b = TargetSelection::from_user("B"); + let a = TargetSelection::from_user("A-A"); + let b = TargetSelection::from_user("B-B"); assert_eq!( first(cache.all::()), @@ -344,10 +364,10 @@ mod dist { #[test] fn dist_with_hosts() { - let mut cache = run_build(&[], configure(&["A", "B"], &["A", "B"])); + let mut cache = run_build(&[], configure(&["A-A", "B-B"], &["A-A", "B-B"])); - let a = TargetSelection::from_user("A"); - let b = TargetSelection::from_user("B"); + let a = TargetSelection::from_user("A-A"); + let b = TargetSelection::from_user("B-B"); assert_eq!( first(cache.all::()), @@ -386,8 +406,8 @@ mod dist { #[test] fn dist_only_cross_host() { - let b = TargetSelection::from_user("B"); - let mut config = configure(&["A", "B"], &["A", "B"]); + let b = TargetSelection::from_user("B-B"); + let mut config = configure(&["A-A", "B-B"], &["A-A", "B-B"]); config.docs = false; config.extended = true; config.hosts = vec![b]; @@ -405,11 +425,11 @@ mod dist { #[test] fn dist_with_targets_and_hosts() { - let mut cache = run_build(&[], configure(&["A", "B"], &["A", "B", "C"])); + let mut cache = run_build(&[], configure(&["A-A", "B-B"], &["A-A", "B-B", "C-C"])); - let a = TargetSelection::from_user("A"); - let b = TargetSelection::from_user("B"); - let c = TargetSelection::from_user("C"); + let a = TargetSelection::from_user("A-A"); + let b = TargetSelection::from_user("B-B"); + let c = TargetSelection::from_user("C-C"); assert_eq!( first(cache.all::()), @@ -439,11 +459,11 @@ mod dist { #[test] fn dist_with_empty_host() { - let config = configure(&[], &["C"]); + let config = configure(&[], &["C-C"]); let mut cache = run_build(&[], config); - let a = TargetSelection::from_user("A"); - let c = TargetSelection::from_user("C"); + let a = TargetSelection::from_user("A-A"); + let c = TargetSelection::from_user("C-C"); assert_eq!(first(cache.all::()), &[dist::Docs { host: c },]); assert_eq!(first(cache.all::()), &[dist::Mingw { host: c },]); @@ -455,10 +475,10 @@ mod dist { #[test] fn dist_with_same_targets_and_hosts() { - let mut cache = run_build(&[], configure(&["A", "B"], &["A", "B"])); + let mut cache = run_build(&[], configure(&["A-A", "B-B"], &["A-A", "B-B"])); - let a = TargetSelection::from_user("A"); - let b = TargetSelection::from_user("B"); + let a = TargetSelection::from_user("A-A"); + let b = TargetSelection::from_user("B-B"); assert_eq!( first(cache.all::()), @@ -506,7 +526,7 @@ mod dist { #[test] fn build_all() { - let build = Build::new(configure(&["A", "B"], &["A", "B", "C"])); + let build = Build::new(configure(&["A-A", "B-B"], &["A-A", "B-B", "C-C"])); let mut builder = Builder::new(&build); builder.run_step_descriptions( &Builder::get_step_descriptions(Kind::Build), @@ -539,29 +559,29 @@ mod dist { #[test] fn llvm_out_behaviour() { - let mut config = configure(&["A"], &["B"]); + let mut config = configure(&["A-A"], &["B-B"]); config.llvm_from_ci = true; let build = Build::new(config.clone()); - let target = TargetSelection::from_user("A"); + let target = TargetSelection::from_user("A-A"); assert!(build.llvm_out(target).ends_with("ci-llvm")); - let target = TargetSelection::from_user("B"); + let target = TargetSelection::from_user("B-B"); assert!(build.llvm_out(target).ends_with("llvm")); config.llvm_from_ci = false; let build = Build::new(config.clone()); - let target = TargetSelection::from_user("A"); + let target = TargetSelection::from_user("A-A"); assert!(build.llvm_out(target).ends_with("llvm")); } #[test] fn build_with_empty_host() { - let config = configure(&[], &["C"]); + let config = configure(&[], &["C-C"]); let build = Build::new(config); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); - let a = TargetSelection::from_user("A"); + let a = TargetSelection::from_user("A-A"); assert_eq!( first(builder.cache.all::()), @@ -583,7 +603,7 @@ mod dist { #[test] fn test_with_no_doc_stage0() { - let mut config = configure(&["A"], &["A"]); + let mut config = configure(&["A-A"], &["A-A"]); config.stage = 0; config.paths = vec!["library/std".into()]; config.cmd = Subcommand::Test { @@ -605,7 +625,7 @@ mod dist { let build = Build::new(config); let mut builder = Builder::new(&build); - let host = TargetSelection::from_user("A"); + let host = TargetSelection::from_user("A-A"); builder.run_step_descriptions( &[StepDescription::from::(Kind::Test)], @@ -627,13 +647,13 @@ mod dist { #[test] fn doc_ci() { - let mut config = configure(&["A"], &["A"]); + let mut config = configure(&["A-A"], &["A-A"]); config.compiler_docs = true; config.cmd = Subcommand::Doc { open: false, json: false }; let build = Build::new(config); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), &[]); - let a = TargetSelection::from_user("A"); + let a = TargetSelection::from_user("A-A"); // error_index_generator uses stage 1 to share rustdoc artifacts with the // rustdoc tool. @@ -656,7 +676,7 @@ mod dist { #[test] fn test_docs() { // Behavior of `x.py test` doing various documentation tests. - let mut config = configure(&["A"], &["A"]); + let mut config = configure(&["A-A"], &["A-A"]); config.cmd = Subcommand::Test { test_args: vec![], rustc_args: vec![], @@ -678,7 +698,7 @@ mod dist { let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]); - let a = TargetSelection::from_user("A"); + let a = TargetSelection::from_user("A-A"); // error_index_generator uses stage 1 to share rustdoc artifacts with the // rustdoc tool. diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 0167c51fc7e2e..bb51433a3dce4 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -181,7 +181,7 @@ pub struct Config { pub test_compare_mode: bool, pub color: Color, pub patch_binaries_for_nix: Option, - pub stage0_metadata: Stage0Metadata, + pub stage0_metadata: build_helper::stage0_parser::Stage0, pub android_ndk: Option, /// Whether to use the `c` feature of the `compiler_builtins` crate. pub optimized_compiler_builtins: bool, @@ -351,34 +351,6 @@ pub struct Config { pub paths: Vec, } -#[derive(Default, Deserialize, Clone)] -pub struct Stage0Metadata { - pub compiler: CompilerMetadata, - pub config: Stage0Config, - pub checksums_sha256: HashMap, - pub rustfmt: Option, -} -#[derive(Default, Deserialize, Clone)] -pub struct CompilerMetadata { - pub date: String, - pub version: String, -} - -#[derive(Default, Deserialize, Clone)] -pub struct Stage0Config { - pub dist_server: String, - pub artifacts_server: String, - pub artifacts_with_llvm_assertions_server: String, - pub git_merge_commit_email: String, - pub git_repository: String, - pub nightly_branch: String, -} -#[derive(Default, Deserialize, Clone)] -pub struct RustfmtMetadata { - pub date: String, - pub version: String, -} - #[derive(Clone, Debug, Default)] pub enum RustfmtState { SystemToolchain(PathBuf), @@ -1298,13 +1270,13 @@ impl Config { Some(p) => PathBuf::from(p), None => git_root, }; - // If this doesn't have at least `stage0.json`, we guessed wrong. This can happen when, + // If this doesn't have at least `stage0`, we guessed wrong. This can happen when, // for example, the build directory is inside of another unrelated git directory. // In that case keep the original `CARGO_MANIFEST_DIR` handling. // // NOTE: this implies that downloadable bootstrap isn't supported when the build directory is outside // the source directory. We could fix that by setting a variable from all three of python, ./x, and x.ps1. - if git_root.join("src").join("stage0.json").exists() { + if git_root.join("src").join("stage0").exists() { config.src = git_root; } } else { @@ -1322,9 +1294,7 @@ impl Config { .to_path_buf(); } - let stage0_json = t!(std::fs::read(config.src.join("src").join("stage0.json"))); - - config.stage0_metadata = t!(serde_json::from_slice::(&stage0_json)); + config.stage0_metadata = build_helper::stage0_parser::parse_stage0_file(); // Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`, then `config.toml` in the root directory. let toml_path = flags diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 75e0f646da699..a074d53aa36e6 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -9,9 +9,9 @@ use std::{ }; use build_helper::ci::CiEnv; +use build_helper::stage0_parser::VersionMetadata; use xz2::bufread::XzDecoder; -use crate::core::config::RustfmtMetadata; use crate::utils::helpers::{check_run, exe, program_out_of_date}; use crate::{core::build_steps::llvm::detect_llvm_sha, utils::helpers::hex_encode}; use crate::{t, Config}; @@ -408,7 +408,7 @@ impl Config { /// NOTE: rustfmt is a completely different toolchain than the bootstrap compiler, so it can't /// reuse target directories or artifacts pub(crate) fn maybe_download_rustfmt(&self) -> Option { - let RustfmtMetadata { date, version } = self.stage0_metadata.rustfmt.as_ref()?; + let VersionMetadata { date, version } = self.stage0_metadata.rustfmt.as_ref()?; let channel = format!("{version}-{date}"); let host = self.build; @@ -606,7 +606,7 @@ impl Config { DownloadSource::Dist => { let dist_server = env::var("RUSTUP_DIST_SERVER") .unwrap_or(self.stage0_metadata.config.dist_server.to_string()); - // NOTE: make `dist` part of the URL because that's how it's stored in src/stage0.json + // NOTE: make `dist` part of the URL because that's how it's stored in src/stage0 (dist_server, format!("dist/{key}/{filename}"), true) } }; @@ -616,7 +616,7 @@ impl Config { // this on each and every nightly ... let checksum = if should_verify { let error = format!( - "src/stage0.json doesn't contain a checksum for {url}. \ + "src/stage0 doesn't contain a checksum for {url}. \ Pre-built artifacts might not be available for this \ target at this time, see https://doc.rust-lang.org/nightly\ /rustc/platform-support.html for more information." diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 0c069a540696f..493ad99cc705b 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -192,7 +192,7 @@ than building it. let target_str = target.to_string(); // Ignore fake targets that are only used for unit tests in bootstrap. - if !["A", "B", "C"].contains(&target_str.as_str()) { + if !["A-A", "B-B", "C-C"].contains(&target_str.as_str()) { let mut has_target = false; let supported_target_list = diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index c599709a32279..698a576effa63 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -683,6 +683,8 @@ impl Build { if !self.config.dry_run() { { + // We first do a dry-run. This is a sanity-check to ensure that + // steps don't do anything expensive in the dry-run. self.config.dry_run = DryRun::SelfCheck; let builder = builder::Builder::new(self); builder.execute_cli(); @@ -1723,7 +1725,7 @@ impl Build { return; } let _ = fs::remove_file(dst); - let metadata = t!(src.symlink_metadata()); + let metadata = t!(src.symlink_metadata(), format!("src = {}", src.display())); let mut src = src.to_path_buf(); if metadata.file_type().is_symlink() { if dereference_symlinks { diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 928c9aa4dff44..0d2ff4f951b61 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -296,6 +296,15 @@ pub fn up_to_date(src: &Path, dst: &Path) -> bool { } } +/// Returns the filename without the hash prefix added by the cc crate. +/// +/// Since v1.0.78 of the cc crate, object files are prefixed with a 16-character hash +/// to avoid filename collisions. +pub fn unhashed_basename(obj: &Path) -> &str { + let basename = obj.file_stem().unwrap().to_str().expect("UTF-8 file name"); + basename.split_once('-').unwrap().1 +} + fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool { t!(fs::read_dir(src)).map(|e| t!(e)).all(|e| { let meta = t!(e.metadata()); diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 462b76d03bd25..5c9918bce32e1 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -215,8 +215,8 @@ impl<'a> Renderer<'a> { for bench in &self.benches { rows.push(( &bench.name, - format!("{:.2?}/iter", Duration::from_nanos(bench.median)), - format!("+/- {:.2?}", Duration::from_nanos(bench.deviation)), + format!("{:.2?}/iter", bench.median), + format!("+/- {:.2?}", bench.deviation), )); } @@ -394,8 +394,8 @@ enum TestMessage { #[derive(serde_derive::Deserialize)] struct BenchOutcome { name: String, - median: u64, - deviation: u64, + median: f64, + deviation: f64, } #[derive(serde_derive::Deserialize)] diff --git a/src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile index dab0667ed55c4..e718437aaaa39 100644 --- a/src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile @@ -25,5 +25,5 @@ ENV CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc \ ENV HOSTS=armv7-unknown-linux-gnueabihf -ENV RUST_CONFIGURE_ARGS --enable-full-tools --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-full-tools --enable-profiler --disable-docs ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh index 005f4537c84ab..f3591a69beee6 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh @@ -4,6 +4,7 @@ set -ex source shared.sh +# Try to keep the LLVM version here in sync with src/ci/scripts/install-clang.sh LLVM=llvmorg-18.1.0 mkdir llvm-project diff --git a/src/ci/docker/scripts/fuchsia-test-runner.py b/src/ci/docker/scripts/fuchsia-test-runner.py index 8ac00a8863f6f..4f504341d5266 100755 --- a/src/ci/docker/scripts/fuchsia-test-runner.py +++ b/src/ci/docker/scripts/fuchsia-test-runner.py @@ -9,10 +9,8 @@ import argparse from dataclasses import dataclass -import fcntl import glob import hashlib -import io import json import os import platform @@ -143,6 +141,14 @@ def subprocess_output(self): return sys.stdout return subprocess.DEVNULL + def check_call(self, args, **kwargs): + self.log_info(f"Running: {' '.join(args)}") + return subprocess.check_call(args, **kwargs) + + def check_output(self, args, **kwargs): + self.log_info(f"Running: {' '.join(args)}") + return subprocess.check_output(args, **kwargs) + def ffx_daemon_log_path(self): return os.path.join(self.tmp_dir(), "ffx_daemon_log") @@ -178,7 +184,7 @@ def start_ffx_isolation(self): ) # Disable analytics - subprocess.check_call( + self.check_call( [ ffx_path, "config", @@ -197,7 +203,7 @@ def start_ffx_isolation(self): "test.experimental_structured_output": "true", } for key, value in configs.items(): - subprocess.check_call( + self.check_call( [ ffx_path, "config", @@ -222,7 +228,7 @@ def ffx_cmd_env(self): } def stop_ffx_isolation(self): - subprocess.check_call( + self.check_call( [ self.tool_path("ffx"), "daemon", @@ -265,7 +271,7 @@ def start(self): self.start_ffx_isolation() # Stop any running emulators (there shouldn't be any) - subprocess.check_call( + self.check_call( [ ffx_path, "emu", @@ -282,11 +288,11 @@ def start(self): product_name = "minimal." + self.triple_to_arch(self.target) fuchsia_version = "20.20240412.3.1" - # FIXME: We should be able to replace this with the machine parsable - # `ffx --machine json product lookup ...` once F15 is released. - out = subprocess.check_output( + out = self.check_output( [ ffx_path, + "--machine", + "json", "product", "lookup", product_name, @@ -300,16 +306,15 @@ def start(self): self.log_debug(out) - for line in io.BytesIO(out): - if line.startswith(b"gs://"): - transfer_manifest_url = line.rstrip() - break - else: - raise Exception("Unable to parse transfer manifest") + try: + transfer_manifest_url = json.loads(out)["transfer_manifest_url"] + except Exception as e: + print(e) + raise Exception("Unable to parse transfer manifest") from e # Download the product bundle. product_bundle_dir = os.path.join(self.tmp_dir(), 'product-bundle') - subprocess.check_call( + self.check_call( [ ffx_path, "product", @@ -325,7 +330,7 @@ def start(self): # Start emulator # FIXME: condition --accel hyper on target arch matching host arch - subprocess.check_call( + self.check_call( [ ffx_path, "emu", @@ -346,42 +351,52 @@ def start(self): # Create new package repo self.log_info("Creating package repo...") - subprocess.check_call( + self.check_call( [ - self.tool_path("pm"), - "newrepo", - "-repo", + ffx_path, + "repository", + "create", self.repo_dir(), ], + env=ffx_env, stdout=self.subprocess_output(), stderr=self.subprocess_output(), ) - # Add repo - subprocess.check_call( + self.check_call( [ ffx_path, "repository", "add-from-pm", - self.repo_dir(), "--repository", self.TEST_REPO_NAME, + self.repo_dir(), ], env=ffx_env, stdout=self.subprocess_output(), stderr=self.subprocess_output(), ) + # Write to file + self.write_to_file() + # Start repository server - subprocess.check_call( - [ffx_path, "repository", "server", "start", "--address", "[::]:0"], + self.check_call( + [ + ffx_path, + "repository", + "server", + "start", + "--address", + "[::]:0", + ], env=ffx_env, stdout=self.subprocess_output(), stderr=self.subprocess_output(), ) # Register with newly-started emulator - subprocess.check_call( + self.check_call( [ ffx_path, "target", @@ -395,12 +410,6 @@ def start(self): stderr=self.subprocess_output(), ) - # Create lockfiles - open(self.pm_lockfile_path(), "a").close() - - # Write to file - self.write_to_file() - self.log_info("Success! Your environment is ready to run tests.") # FIXME: shardify this @@ -445,7 +454,6 @@ def start(self): meta/{package_name}.cm={package_dir}/meta/{package_name}.cm bin/{exe_name}={bin_path} lib/{libstd_name}={libstd_path} - lib/{libtest_name}={libtest_path} lib/ld.so.1={sdk_dir}/arch/{target_arch}/sysroot/dist/lib/ld.so.1 lib/libfdio.so={sdk_dir}/arch/{target_arch}/dist/libfdio.so """ @@ -482,9 +490,6 @@ def run(self, args): if not libstd_paths: raise Exception(f"Failed to locate libstd (in {self.rustlibs_dir()})") - if not libtest_paths: - raise Exception(f"Failed to locate libtest (in {self.rustlibs_dir()})") - # Build a unique, deterministic name for the test using the name of the # binary and the last 6 hex digits of the hash of the full path def path_checksum(path): @@ -500,6 +505,7 @@ def path_checksum(path): cml_path = os.path.join(package_dir, "meta", f"{package_name}.cml") cm_path = os.path.join(package_dir, "meta", f"{package_name}.cm") manifest_path = os.path.join(package_dir, f"{package_name}.manifest") + manifest_json_path = os.path.join(package_dir, "package_manifest.json") far_path = os.path.join(package_dir, f"{package_name}-0.far") shared_libs = args.shared_libs[: args.n] @@ -523,22 +529,6 @@ def log(msg): log(f"Bin path: {bin_path}") - log("Setting up package...") - - # Set up package - subprocess.check_call( - [ - self.tool_path("pm"), - "-o", - package_dir, - "-n", - package_name, - "init", - ], - stdout=log_file, - stderr=log_file, - ) - log("Writing CML...") # Write and compile CML @@ -563,7 +553,7 @@ def log(msg): log("Compiling CML...") - subprocess.check_call( + self.check_call( [ self.tool_path("cmc"), "compile", @@ -590,38 +580,61 @@ def log(msg): target=self.target, sdk_dir=self.sdk_dir, libstd_name=os.path.basename(libstd_paths[0]), - libtest_name=os.path.basename(libtest_paths[0]), libstd_path=libstd_paths[0], - libtest_path=libtest_paths[0], target_arch=self.triple_to_arch(self.target), ) ) + # `libtest`` was historically a shared library, but now seems to be (sometimes?) + # statically linked. If we find it as a shared library, include it in the manifest. + if libtest_paths: + manifest.write( + f"lib/{os.path.basename(libtest_paths[0])}={libtest_paths[0]}\n" + ) for shared_lib in shared_libs: manifest.write(f"lib/{os.path.basename(shared_lib)}={shared_lib}\n") + log("Determining API level...") + out = self.check_output( + [ + self.tool_path("ffx"), + "--machine", + "json", + "version", + ], + env=self.ffx_cmd_env(), + stderr=log_file, + ) + api_level = json.loads(out)["tool_version"]["api_level"] + log("Compiling and archiving manifest...") - subprocess.check_call( + self.check_call( [ - self.tool_path("pm"), + self.tool_path("ffx"), + "package", + "build", + manifest_path, "-o", package_dir, - "-m", - manifest_path, - "build", + "--api-level", + str(api_level), ], + env=self.ffx_cmd_env(), stdout=log_file, stderr=log_file, ) - subprocess.check_call( + + self.check_call( [ - self.tool_path("pm"), - "-o", - package_dir, - "-m", - manifest_path, + self.tool_path("ffx"), + "package", "archive", + "create", + "-o", + far_path, + manifest_json_path, ], + env=self.ffx_cmd_env(), stdout=log_file, stderr=log_file, ) @@ -629,25 +642,18 @@ def log(msg): log("Publishing package to repo...") # Publish package to repo - with open(self.pm_lockfile_path(), "w") as pm_lockfile: - fcntl.lockf(pm_lockfile.fileno(), fcntl.LOCK_EX) - subprocess.check_call( - [ - self.tool_path("pm"), - "publish", - "-a", - "-repo", - self.repo_dir(), - "-f", - far_path, - ], - stdout=log_file, - stderr=log_file, - ) - # This lock should be released automatically when the pm - # lockfile is closed, but we'll be polite and unlock it now - # since the spec leaves some wiggle room. - fcntl.lockf(pm_lockfile.fileno(), fcntl.LOCK_UN) + self.check_call( + [ + self.tool_path("ffx"), + "repository", + "publish", + "--package", + os.path.join(package_dir, "package_manifest.json"), + self.repo_dir(), + ], + stdout=log_file, + stderr=log_file, + ) log("Running ffx test...") @@ -765,7 +771,7 @@ def stop(self): # Shut down the emulator self.log_info("Stopping emulator...") - subprocess.check_call( + self.check_call( [ self.tool_path("ffx"), "emu", diff --git a/src/ci/github-actions/calculate-job-matrix.py b/src/ci/github-actions/calculate-job-matrix.py index 68565f489c939..4f9bc39a628ce 100755 --- a/src/ci/github-actions/calculate-job-matrix.py +++ b/src/ci/github-actions/calculate-job-matrix.py @@ -8,10 +8,11 @@ and filters them based on the event that happened on CI. """ import dataclasses -import enum import json import logging import os +import re +import typing from pathlib import Path from typing import List, Dict, Any, Optional @@ -44,10 +45,22 @@ def add_base_env(jobs: List[Job], environment: Dict[str, str]) -> List[Job]: return jobs -class WorkflowRunType(enum.Enum): - PR = enum.auto() - Try = enum.auto() - Auto = enum.auto() +@dataclasses.dataclass +class PRRunType: + pass + + +@dataclasses.dataclass +class TryRunType: + custom_jobs: List[str] + + +@dataclasses.dataclass +class AutoRunType: + pass + + +WorkflowRunType = typing.Union[PRRunType, TryRunType, AutoRunType] @dataclasses.dataclass @@ -55,11 +68,28 @@ class GitHubCtx: event_name: str ref: str repository: str + commit_message: Optional[str] + + +def get_custom_jobs(ctx: GitHubCtx) -> List[str]: + """ + Tries to parse names of specific CI jobs that should be executed in the form of + try-job: + from the commit message of the passed GitHub context. + """ + if ctx.commit_message is None: + return [] + + regex = re.compile(r"^try-job: (.*)", re.MULTILINE) + jobs = [] + for match in regex.finditer(ctx.commit_message): + jobs.append(match.group(1)) + return jobs def find_run_type(ctx: GitHubCtx) -> Optional[WorkflowRunType]: if ctx.event_name == "pull_request": - return WorkflowRunType.PR + return PRRunType() elif ctx.event_name == "push": old_bors_try_build = ( ctx.ref in ("refs/heads/try", "refs/heads/try-perf") and @@ -72,20 +102,41 @@ def find_run_type(ctx: GitHubCtx) -> Optional[WorkflowRunType]: try_build = old_bors_try_build or new_bors_try_build if try_build: - return WorkflowRunType.Try + jobs = get_custom_jobs(ctx) + return TryRunType(custom_jobs=jobs) if ctx.ref == "refs/heads/auto" and ctx.repository == "rust-lang-ci/rust": - return WorkflowRunType.Auto + return AutoRunType() return None def calculate_jobs(run_type: WorkflowRunType, job_data: Dict[str, Any]) -> List[Job]: - if run_type == WorkflowRunType.PR: + if isinstance(run_type, PRRunType): return add_base_env(name_jobs(job_data["pr"], "PR"), job_data["envs"]["pr"]) - elif run_type == WorkflowRunType.Try: - return add_base_env(name_jobs(job_data["try"], "try"), job_data["envs"]["try"]) - elif run_type == WorkflowRunType.Auto: + elif isinstance(run_type, TryRunType): + jobs = job_data["try"] + custom_jobs = run_type.custom_jobs + if custom_jobs: + if len(custom_jobs) > 10: + raise Exception( + f"It is only possible to schedule up to 10 custom jobs, " + f"received {len(custom_jobs)} jobs" + ) + + jobs = [] + unknown_jobs = [] + for custom_job in custom_jobs: + job = [j for j in job_data["auto"] if j["image"] == custom_job] + if not job: + unknown_jobs.append(custom_job) + continue + jobs.append(job[0]) + if unknown_jobs: + raise Exception(f"Custom job(s) `{unknown_jobs}` not found in auto jobs") + + return add_base_env(name_jobs(jobs, "try"), job_data["envs"]["try"]) + elif isinstance(run_type, AutoRunType): return add_base_env(name_jobs(job_data["auto"], "auto"), job_data["envs"]["auto"]) return [] @@ -99,19 +150,25 @@ def skip_jobs(jobs: List[Dict[str, Any]], channel: str) -> List[Job]: def get_github_ctx() -> GitHubCtx: + event_name = os.environ["GITHUB_EVENT_NAME"] + + commit_message = None + if event_name == "push": + commit_message = os.environ["COMMIT_MESSAGE"] return GitHubCtx( - event_name=os.environ["GITHUB_EVENT_NAME"], + event_name=event_name, ref=os.environ["GITHUB_REF"], - repository=os.environ["GITHUB_REPOSITORY"] + repository=os.environ["GITHUB_REPOSITORY"], + commit_message=commit_message ) def format_run_type(run_type: WorkflowRunType) -> str: - if run_type == WorkflowRunType.PR: + if isinstance(run_type, PRRunType): return "pr" - elif run_type == WorkflowRunType.Auto: + elif isinstance(run_type, AutoRunType): return "auto" - elif run_type == WorkflowRunType.Try: + elif isinstance(run_type, TryRunType): return "try" else: raise AssertionError() @@ -135,6 +192,10 @@ def format_run_type(run_type: WorkflowRunType) -> str: if run_type is not None: jobs = calculate_jobs(run_type, data) jobs = skip_jobs(jobs, channel) + + if not jobs: + raise Exception("Scheduled job list is empty, this is an error") + run_type = format_run_type(run_type) logging.info(f"Output:\n{yaml.dump(dict(jobs=jobs, run_type=run_type), indent=4)}") diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 20b1a55ffb879..04888dc09b50d 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -32,14 +32,6 @@ runners: os: windows-2022-16core-64gb <<: *base-job - - &job-windows-2019-8c - os: windows-2019-8core-32gb - <<: *base-job - - - &job-windows-2019-16c - os: windows-2019-16core-64gb - <<: *base-job - - &job-aarch64-linux os: [ self-hosted, ARM64, linux ] @@ -349,13 +341,13 @@ auto: env: RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler SCRIPT: make ci-msvc - <<: *job-windows-2019-8c + <<: *job-windows-8c - image: i686-msvc env: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc SCRIPT: make ci-msvc - <<: *job-windows-2019-8c + <<: *job-windows-8c - image: x86_64-msvc-ext env: @@ -363,7 +355,7 @@ auto: HOST_TARGET: x86_64-pc-windows-msvc RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld --save-toolstates=/tmp/toolstate/toolstates.json DEPLOY_TOOLSTATES_JSON: toolstates-windows.json - <<: *job-windows-2019-8c + <<: *job-windows-8c # 32/64-bit MinGW builds. # @@ -414,7 +406,7 @@ auto: --set rust.codegen-units=1 SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-windows-2019-8c + <<: *job-windows-8c - image: dist-i686-msvc env: @@ -426,7 +418,7 @@ auto: --enable-profiler SCRIPT: python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-windows-2019-8c + <<: *job-windows-8c - image: dist-aarch64-msvc env: @@ -437,7 +429,7 @@ auto: --enable-profiler SCRIPT: python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-windows-2019-8c + <<: *job-windows-8c - image: dist-i686-mingw env: @@ -471,4 +463,4 @@ auto: env: RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler SCRIPT: python x.py dist bootstrap --include-default-paths - <<: *job-windows-2019-8c + <<: *job-windows-8c diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh index aa7ff813f5161..24b9904d65c25 100755 --- a/src/ci/scripts/install-clang.sh +++ b/src/ci/scripts/install-clang.sh @@ -10,18 +10,24 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" # Update both macOS's and Windows's tarballs when bumping the version here. -LLVM_VERSION="14.0.5" +# Try to keep this in sync with src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh +LLVM_VERSION="18.1.4" if isMacOS; then + # FIXME: This is the latest pre-built version of LLVM that's available for + # x86_64 MacOS. We may want to consider bulding our own LLVM binaries + # instead, or set `USE_XCODE_CLANG` like AArch64 does. + LLVM_VERSION="15.0.7" + # If the job selects a specific Xcode version, use that instead of # downloading our own version. if [[ ${USE_XCODE_CLANG-0} -eq 1 ]]; then bindir="$(xcode-select --print-path)/Toolchains/XcodeDefault.xctoolchain/usr/bin" else - file="${MIRRORS_BASE}/clang%2Bllvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz" - retry curl -f "${file}" -o "clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz" - tar xJf "clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz" - bindir="$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin" + file="${MIRRORS_BASE}/clang%2Bllvm-${LLVM_VERSION}-x86_64-apple-darwin21.0.tar.xz" + retry curl -f "${file}" -o "clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin21.0.tar.xz" + tar xJf "clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin21.0.tar.xz" + bindir="$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin21.0/bin" fi ciCommandSetEnv CC "${bindir}/clang" diff --git a/src/doc/book b/src/doc/book index d207d894cc5e1..bebcf527e6775 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit d207d894cc5e1d496ab99beeacd1a420e5d4d238 +Subproject commit bebcf527e67755a989a1739b7cfaa8f0e6b30040 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index aa7d4b0b4653d..17842ebb050f6 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit aa7d4b0b4653ddb47cb1de2036d090ec2ba9dab1 +Subproject commit 17842ebb050f62e40a4618edeb8e8ee86e758707 diff --git a/src/doc/reference b/src/doc/reference index 5854fcc286557..51817951d0d21 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 5854fcc286557ad3ab34d325073d11d8118096b6 +Subproject commit 51817951d0d213a0011f82b62aae02c3b3f2472e diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 60d34b5fd33db..229ad13b64d91 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 60d34b5fd33db1346f9aabfc0c9d0bda6c8e42be +Subproject commit 229ad13b64d919b12e548d560f06d88963b25cd3 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 07425fed36b00..2d1947ff34d50 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 07425fed36b00e60341c5e29e28d37d40cbd4451 +Subproject commit 2d1947ff34d50ca46dfe242ad75531a4c429bb52 diff --git a/src/doc/rustc/src/check-cfg.md b/src/doc/rustc/src/check-cfg.md index 56198437ee97d..8e39adaa43858 100644 --- a/src/doc/rustc/src/check-cfg.md +++ b/src/doc/rustc/src/check-cfg.md @@ -1,18 +1,29 @@ # Checking conditional configurations -`rustc` accepts the `--check-cfg` option, which specifies whether to check conditions and how to -check them. The `--check-cfg` option takes a value, called the _check cfg specification_. -This specification has one form: +`rustc` supports checking that every _reachable_[^reachable] `#[cfg]` matches a list of the +expected config names and values. -1. `--check-cfg cfg(...)` mark a configuration and it's expected values as expected. +This can help with verifying that the crate is correctly handling conditional compilation for +different target platforms or features. It ensures that the cfg settings are consistent between +what is intended and what is used, helping to catch potential bugs or errors early in the +development process. -*No implicit expectation is added when using `--cfg`. Users are expected to -pass all expected names and values using the _check cfg specification_.* +In order to accomplish that goal, `rustc` accepts the `--check-cfg` flag, which specifies +whether to check conditions and how to check them. -## The `cfg(...)` form +> **Note:** No implicit expectation is added when using `--cfg`. Users are expected to +pass all expected names and values using the _check cfg specification_. -The `cfg(...)` form enables checking the values within list-valued conditions. It has this -basic form: +[^reachable]: `rustc` promises to at least check reachable `#[cfg]`, and while non-reachable +`#[cfg]` are not currently checked, they may well be checked in the future without it being a +breaking change. + +## Specifying expected names and values + +To specify expected names and values, the _check cfg specification_ provides the `cfg(...)` +option which enables specifying for an expected config name and it's expected values. + +It has this basic form: ```bash rustc --check-cfg 'cfg(name, values("value1", "value2", ... "valueN"))' @@ -20,15 +31,20 @@ rustc --check-cfg 'cfg(name, values("value1", "value2", ... "valueN"))' where `name` is a bare identifier (has no quotes) and each `"value"` term is a quoted literal string. `name` specifies the name of the condition, such as `feature` or `my_cfg`. +`"value"` specify one of the value of that condition name. + +When the `cfg(...)` option is specified, `rustc` will check every[^reachable]: + - `#[cfg(name = "value")]` attribute + - `#[cfg_attr(name = "value")]` attribute + - `#[link(name = "a", cfg(name = "value"))]` attribute + - `cfg!(name = "value")` macro call -When the `cfg(...)` option is specified, `rustc` will check every `#[cfg(name = "value")]` -attribute, `#[cfg_attr(name = "value")]` attribute, `#[link(name = "a", cfg(name = "value"))]` -attribute and `cfg!(name = "value")` macro call. It will check that the `"value"` specified is -present in the list of expected values. If `"value"` is not in it, then `rustc` will report an -`unexpected_cfgs` lint diagnostic. The default diagnostic level for this lint is `Warn`. +> *The command line `--cfg` arguments are currently NOT checked but may very well be checked +in the future.* -*The command line `--cfg` arguments are currently *NOT* checked but may very well be checked in -the future.* +`rustc` will check that the `"value"` specified is present in the list of expected values. +If `"value"` is not in it, then `rustc` will report an `unexpected_cfgs` lint diagnostic. +The default diagnostic level for this lint is `Warn`. To check for the _none_ value (ie `#[cfg(foo)]`) one can use the `none()` predicate inside `values()`: `values(none())`. It can be followed or preceded by any number of `"value"`. @@ -43,12 +59,12 @@ rustc --check-cfg 'cfg(name, values(none()))' To enable checking of name but not values, use one of these forms: - - No expected values (_will lint on every value_): + - No expected values (_will lint on every value of `name`_): ```bash rustc --check-cfg 'cfg(name, values())' ``` - - Unknown expected values (_will never lint_): + - Unknown expected values (_will never lint on value of `name`_): ```bash rustc --check-cfg 'cfg(name, values(any()))' ``` @@ -59,17 +75,26 @@ To avoid repeating the same set of values, use this form: rustc --check-cfg 'cfg(name1, ..., nameN, values("value1", "value2", ... "valueN"))' ``` +To enable checking without specifying any names or values, use this form: + +```bash +rustc --check-cfg 'cfg()' +``` + The `--check-cfg cfg(...)` option can be repeated, both for the same condition name and for different names. If it is repeated for the same condition name, then the sets of values for that condition are merged together (precedence is given to `values(any())`). +> To help out an equivalence table between `--cfg` arguments and `--check-cfg` is available +[down below](#equivalence-table-with---cfg). + ## Well known names and values -`rustc` has a internal list of well known names and their corresponding values. -Those well known names and values follows the same stability as what they refer to. +`rustc` maintains a list of well-known names and their corresponding values in order to avoid +the need to specify them manually. -Well known names and values checking is always enabled as long as at least one -`--check-cfg` argument is present. +Well known names and values are implicitly added as long as at least one `--check-cfg` argument +is present. As of `2024-05-06T`, the list of known names is as follows: @@ -109,11 +134,9 @@ As of `2024-05-06T`, the list of known names is as follows: Like with `values(any())`, well known names checking can be disabled by passing `cfg(any())` as argument to `--check-cfg`. -## Examples - -### Equivalence table +## Equivalence table with `--cfg` -This table describe the equivalence of a `--cfg` argument to a `--check-cfg` argument. +This table describe the equivalence between a `--cfg` argument to a `--check-cfg` argument. | `--cfg` | `--check-cfg` | |-------------------------------|------------------------------------------------------------| @@ -125,40 +148,42 @@ This table describe the equivalence of a `--cfg` argument to a `--check-cfg` arg | `--cfg foo="1" --cfg bar="2"` | `--check-cfg=cfg(foo, values("1")) --check-cfg=cfg(bar, values("2"))` | | `--cfg foo --cfg foo="bar"` | `--check-cfg=cfg(foo, values(none(), "bar"))` | +## Examples + ### Example: Cargo-like `feature` example Consider this command line: ```bash rustc --check-cfg 'cfg(feature, values("lion", "zebra"))' \ - --cfg 'feature="lion"' -Z unstable-options example.rs + --cfg 'feature="lion"' example.rs ``` -This command line indicates that this crate has two features: `lion` and `zebra`. The `lion` +> This command line indicates that this crate has two features: `lion` and `zebra`. The `lion` feature is enabled, while the `zebra` feature is disabled. -Given the `--check-cfg` arguments, exhaustive checking of names and -values are enabled. -`example.rs`: ```rust -#[cfg(feature = "lion")] // This condition is expected, as "lion" is an expected value of `feature` +#[cfg(feature = "lion")] // This condition is expected, as "lion" is an + // expected value of `feature` fn tame_lion(lion: Lion) {} -#[cfg(feature = "zebra")] // This condition is expected, as "zebra" is an expected value of `feature` - // but the condition will still evaluate to false - // since only --cfg feature="lion" was passed +#[cfg(feature = "zebra")] // This condition is expected, as "zebra" is an expected + // value of `feature` but the condition will evaluate + // to false since only --cfg feature="lion" was passed fn ride_zebra(z: Zebra) {} -#[cfg(feature = "platypus")] // This condition is UNEXPECTED, as "platypus" is NOT an expected value of - // `feature` and will cause a compiler warning (by default). +#[cfg(feature = "platypus")] // This condition is UNEXPECTED, as "platypus" is NOT + // an expected value of `feature` and will cause a + // the compiler to emit the `unexpected_cfgs` lint fn poke_platypus() {} -#[cfg(feechure = "lion")] // This condition is UNEXPECTED, as 'feechure' is NOT a expected condition - // name, no `cfg(feechure, ...)` was passed in `--check-cfg` +#[cfg(feechure = "lion")] // This condition is UNEXPECTED, as 'feechure' is NOT + // a expected condition name, no `cfg(feechure, ...)` + // was passed in `--check-cfg` fn tame_lion() {} -#[cfg(windows = "unix")] // This condition is UNEXPECTED, as while 'windows' is a well known - // condition name, it doesn't expect any values +#[cfg(windows = "unix")] // This condition is UNEXPECTED, as the well known + // 'windows' cfg doesn't expect any values fn tame_windows() {} ``` @@ -167,25 +192,28 @@ fn tame_windows() {} ```bash rustc --check-cfg 'cfg(is_embedded, has_feathers)' \ --check-cfg 'cfg(feature, values("zapping", "lasers"))' \ - --cfg has_feathers --cfg 'feature="zapping"' -Z unstable-options + --cfg has_feathers --cfg 'feature="zapping"' ``` ```rust -#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was provided in --check-cfg -fn do_embedded() {} // and doesn't take any value +#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was + // provided in --check-cfg and doesn't take any value +fn do_embedded() {} -#[cfg(has_feathers)] // This condition is expected, as 'has_feathers' was provided in --check-cfg -fn do_features() {} // and doesn't take any value +#[cfg(has_feathers)] // This condition is expected, as 'has_feathers' was + // provided in --check-cfg and doesn't take any value +fn do_features() {} -#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' was NEVER provided - // in any --check-cfg arguments +#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' + // was NEVER provided in any --check-cfg arguments fn do_mumble_frotz() {} -#[cfg(feature = "lasers")] // This condition is expected, as "lasers" is an expected value of `feature` +#[cfg(feature = "lasers")] // This condition is expected, as "lasers" is an + // expected value of `feature` fn shoot_lasers() {} -#[cfg(feature = "monkeys")] // This condition is UNEXPECTED, as "monkeys" is NOT an expected value of - // `feature` +#[cfg(feature = "monkeys")] // This condition is UNEXPECTED, as "monkeys" is NOT + // an expected value of `feature` fn write_shakespeare() {} ``` @@ -193,24 +221,25 @@ fn write_shakespeare() {} ```bash rustc --check-cfg 'cfg(is_embedded, has_feathers, values(any()))' \ - --cfg has_feathers -Z unstable-options + --cfg has_feathers ``` ```rust -#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was provided in --check-cfg - // as condition name +#[cfg(is_embedded)] // This condition is expected, as 'is_embedded' was + // provided in --check-cfg as condition name fn do_embedded() {} -#[cfg(has_feathers)] // This condition is expected, as "has_feathers" was provided in --check-cfg - // as condition name +#[cfg(has_feathers)] // This condition is expected, as "has_feathers" was + // provided in --check-cfg as condition name fn do_features() {} -#[cfg(has_feathers = "zapping")] // This condition is expected, as "has_feathers" was provided in - // and because *any* values is expected for 'has_feathers' no +#[cfg(has_feathers = "zapping")] // This condition is expected, as "has_feathers" + // was provided and because *any* values is + // expected for 'has_feathers' no // warning is emitted for the value "zapping" fn do_zapping() {} -#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' was not provided - // in any --check-cfg arguments +#[cfg(has_mumble_frotz)] // This condition is UNEXPECTED, as 'has_mumble_frotz' + // was not provided in any --check-cfg arguments fn do_mumble_frotz() {} ``` diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 7c605333c25d4..3e1ac2fa8ad7b 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -19,9 +19,15 @@ For examples, `--cfg 'verbose'` or `--cfg 'feature="serde"'`. These correspond to `#[cfg(verbose)]` and `#[cfg(feature = "serde")]` respectively. -## `--check-cfg`: enables checking conditional configurations +## `--check-cfg`: configure compile-time checking of conditional compilation + +This flag enables checking conditional configurations of the crate at compile-time, +specifically it helps configure the set of expected cfg names and values, in order +to check that every _reachable_ `#[cfg]` matches the expected config names and values. + +This is different from the `--cfg` flag above which activates some config but do +not expect them. This is useful to prevent stalled conditions, typos, ... -This flag will enable checking conditional configurations. Refer to the [Checking conditional configurations](check-cfg.md) of this book for further details and explanation. diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index 34ab3cdaf25e5..9c2e05b57f5e8 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -683,25 +683,37 @@ cd ${RUST_SRC_PATH} To run the Rust test suite on an emulated Fuchsia device, you'll also need to download a copy of the Fuchsia SDK. The current minimum supported SDK version is -[10.20221207.2.89][minimum_supported_sdk_version]. +[20.20240412.3.1][minimum_supported_sdk_version]. -[minimum_supported_sdk_version]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core/linux-amd64/+/version:10.20221207.2.89 +[minimum_supported_sdk_version]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core/linux-amd64/+/version:20.20240412.3.1 Fuchsia's test runner interacts with the Fuchsia emulator and is located at -`src/ci/docker/scripts/fuchsia-test-runner.py`. We can use it to start our -test environment with: +`src/ci/docker/scripts/fuchsia-test-runner.py`. First, add the following +variables to your existing `config-env.sh`: + +```sh +# TEST_TOOLCHAIN_TMP_DIR can point anywhere, but it: +# - must be less than 108 characters, otherwise qemu can't handle the path +# - must be consistent across calls to this file (don't use `mktemp -d` here) +export TEST_TOOLCHAIN_TMP_DIR="/tmp/rust-tmp" + +# Keep existing contents of `config-env.sh` from earlier, including SDK_PATH +``` + +We can then use the script to start our test environment with: ```sh ( \ + source config-env.sh && \ src/ci/docker/scripts/fuchsia-test-runner.py start \ --rust-build ${RUST_SRC_PATH}/build \ --sdk ${SDK_PATH} \ --target {x86_64-unknown-fuchsia|aarch64-unknown-fuchsia} \ + --verbose \ ) ``` -Where `${RUST_SRC_PATH}/build` is the `build-dir` set in `config.toml` and -`${SDK_PATH}` is the path to the downloaded and unzipped SDK. +Where `${RUST_SRC_PATH}/build` is the `build-dir` set in `config.toml`. Once our environment is started, we can run our tests using `x.py` as usual. The test runner script will run the compiled tests on an emulated Fuchsia device. To diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md index 822f341b370af..69fb7e3313fe9 100644 --- a/src/doc/rustdoc/src/command-line-arguments.md +++ b/src/doc/rustdoc/src/command-line-arguments.md @@ -273,7 +273,7 @@ will be added. When rendering Rust files, this flag is ignored. -## `--html-in-header`: include more HTML in +## `--html-in-header`: include more HTML in `` Using this flag looks like this: diff --git a/src/etc/lldb_lookup.py b/src/etc/lldb_lookup.py index a93b42e1cc449..db3afb00369da 100644 --- a/src/etc/lldb_lookup.py +++ b/src/etc/lldb_lookup.py @@ -86,7 +86,8 @@ def synthetic_lookup(valobj, dict): return synthetic_lookup(valobj.GetChildAtIndex(discriminant), dict) if rust_type == RustType.SINGLETON_ENUM: return synthetic_lookup(valobj.GetChildAtIndex(0), dict) - + if rust_type == RustType.ENUM: + return ClangEncodedEnumProvider(valobj, dict) if rust_type == RustType.STD_VEC: return StdVecSyntheticProvider(valobj, dict) if rust_type == RustType.STD_VEC_DEQUE: diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 1c43977a501a0..a87fd6078b866 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -247,6 +247,58 @@ def has_children(self): # type: () -> bool return True +class ClangEncodedEnumProvider: + """Pretty-printer for 'clang-encoded' enums support implemented in LLDB""" + DISCRIMINANT_MEMBER_NAME = "$discr$" + VALUE_MEMBER_NAME = "value" + + def __init__(self, valobj, dict): + self.valobj = valobj + self.update() + + def has_children(self): + return True + + def num_children(self): + if self.is_default: + return 1 + return 2 + + def get_child_index(self, name): + if name == ClangEncodedEnumProvider.VALUE_MEMBER_NAME: + return 0 + if name == ClangEncodedEnumProvider.DISCRIMINANT_MEMBER_NAME: + return 1 + return -1 + + def get_child_at_index(self, index): + if index == 0: + return self.variant.GetChildMemberWithName(ClangEncodedEnumProvider.VALUE_MEMBER_NAME) + if index == 1: + return self.variant.GetChildMemberWithName( + ClangEncodedEnumProvider.DISCRIMINANT_MEMBER_NAME) + + + def update(self): + all_variants = self.valobj.GetChildAtIndex(0) + index = self._getCurrentVariantIndex(all_variants) + self.variant = all_variants.GetChildAtIndex(index) + self.is_default = self.variant.GetIndexOfChildWithName( + ClangEncodedEnumProvider.DISCRIMINANT_MEMBER_NAME) == -1 + + def _getCurrentVariantIndex(self, all_variants): + default_index = 0 + for i in range(all_variants.GetNumChildren()): + variant = all_variants.GetChildAtIndex(i) + discr = variant.GetChildMemberWithName( + ClangEncodedEnumProvider.DISCRIMINANT_MEMBER_NAME) + if discr.IsValid(): + discr_unsigned_value = discr.GetValueAsUnsigned() + if variant.GetName() == f"$variant${discr_unsigned_value}": + return i + else: + default_index = i + return default_index class TupleSyntheticProvider: """Pretty-printer for tuples and tuple enum variants""" diff --git a/src/etc/rust_types.py b/src/etc/rust_types.py index c0415a3cdcfe4..190fbc13a173f 100644 --- a/src/etc/rust_types.py +++ b/src/etc/rust_types.py @@ -60,6 +60,7 @@ class RustType(object): ENCODED_ENUM_PREFIX = "RUST$ENCODED$ENUM$" ENUM_DISR_FIELD_NAME = "<>" +ENUM_LLDB_ENCODED_VARIANTS = "$variants$" STD_TYPE_TO_REGEX = { RustType.STD_STRING: STD_STRING_REGEX, @@ -96,7 +97,11 @@ def classify_struct(name, fields): if regex.match(name): return ty - if fields[0].name == ENUM_DISR_FIELD_NAME: + # <> is emitted by GDB while LLDB(18.1+) emits "$variants$" + if ( + fields[0].name == ENUM_DISR_FIELD_NAME + or fields[0].name == ENUM_LLDB_ENCODED_VARIANTS + ): return RustType.ENUM if is_tuple_fields(fields): diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index daf63998461ee..c464820413cf5 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -150,7 +150,7 @@ fn clean_param_env<'tcx>( let generics = tcx.generics_of(item_def_id); let params: ThinVec<_> = generics - .params + .own_params .iter() .inspect(|param| { if cfg!(debug_assertions) { @@ -326,7 +326,7 @@ fn clean_region_outlives_constraints<'tcx>( } let region_params: FxIndexSet<_> = generics - .params + .own_params .iter() .filter_map(|param| match param.kind { ty::GenericParamDefKind::Lifetime => Some(param.name), diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 4d506edc47bd4..7d8b6f34cbb4e 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -14,6 +14,7 @@ use rustc_hir::Mutability; use rustc_metadata::creader::{CStore, LoadedMacro}; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::def_id::LOCAL_CRATE; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; @@ -444,24 +445,24 @@ pub(crate) fn build_impl( let associated_trait = tcx.impl_trait_ref(did).map(ty::EarlyBinder::skip_binder); + // Do not inline compiler-internal items unless we're a compiler-internal crate. + let is_compiler_internal = |did| { + tcx.lookup_stability(did) + .is_some_and(|stab| stab.is_unstable() && stab.feature == sym::rustc_private) + }; + let document_compiler_internal = is_compiler_internal(LOCAL_CRATE.as_def_id()); + let is_directly_public = |cx: &mut DocContext<'_>, did| { + cx.cache.effective_visibilities.is_directly_public(tcx, did) + && (document_compiler_internal || !is_compiler_internal(did)) + }; + // Only inline impl if the implemented trait is // reachable in rustdoc generated documentation if !did.is_local() && let Some(traitref) = associated_trait + && !is_directly_public(cx, traitref.def_id) { - let did = traitref.def_id; - if !cx.cache.effective_visibilities.is_directly_public(tcx, did) { - return; - } - - if !tcx.features().rustc_private && !cx.render_options.force_unstable_if_unmarked { - if let Some(stab) = tcx.lookup_stability(did) - && stab.is_unstable() - && stab.feature == sym::rustc_private - { - return; - } - } + return; } let impl_item = match did.as_local() { @@ -484,21 +485,11 @@ pub(crate) fn build_impl( // Only inline impl if the implementing type is // reachable in rustdoc generated documentation - if !did.is_local() { - if let Some(did) = for_.def_id(&cx.cache) { - if !cx.cache.effective_visibilities.is_directly_public(tcx, did) { - return; - } - - if !tcx.features().rustc_private && !cx.render_options.force_unstable_if_unmarked { - if let Some(stab) = tcx.lookup_stability(did) - && stab.is_unstable() - && stab.feature == sym::rustc_private - { - return; - } - } - } + if !did.is_local() + && let Some(did) = for_.def_id(&cx.cache) + && !is_directly_public(cx, did) + { + return; } let document_hidden = cx.render_options.document_hidden; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f437c7d319d75..90f2e3d09fe86 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -795,7 +795,7 @@ fn clean_ty_generics<'tcx>( let mut impl_trait = BTreeMap::>::default(); let params: ThinVec<_> = gens - .params + .own_params .iter() .filter(|param| match param.kind { ty::GenericParamDefKind::Lifetime => !param.is_anonymous_lifetime(), @@ -1860,9 +1860,9 @@ fn normalize<'tcx>( return None; } - use crate::rustc_trait_selection::infer::TyCtxtInferExt; - use crate::rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_middle::traits::ObligationCause; + use rustc_trait_selection::infer::TyCtxtInferExt; + use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; // Try to normalize `::T` to a type let infcx = cx.tcx.infer_ctxt().build(); @@ -1988,7 +1988,7 @@ impl<'tcx> ContainerTy<'_, 'tcx> { let generics = tcx.generics_of(container); debug_assert_eq!(generics.parent_count, 0); - let param = generics.params[index].def_id; + let param = generics.own_params[index].def_id; let default = tcx.object_lifetime_default(param); match default { rbv::ObjectLifetimeDefault::Param(lifetime) => { diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 465f969435d1b..d4468fecba402 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -285,8 +285,6 @@ pub(crate) struct RenderOptions { pub(crate) no_emit_shared: bool, /// If `true`, HTML source code pages won't be generated. pub(crate) html_no_source: bool, - /// Whether `-Zforce-unstable-if-unmarked` unstable option is set - pub(crate) force_unstable_if_unmarked: bool, } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -353,7 +351,6 @@ impl Options { let codegen_options = CodegenOptions::build(early_dcx, matches); let unstable_opts = UnstableOptions::build(early_dcx, matches); - let force_unstable_if_unmarked = unstable_opts.force_unstable_if_unmarked; let dcx = new_dcx(error_format, None, diagnostic_width, &unstable_opts); @@ -790,7 +787,6 @@ impl Options { call_locations, no_emit_shared: false, html_no_source, - force_unstable_if_unmarked, }; Some((options, render_options)) } diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index 57e82b877bf14..6beca8bdb3a68 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -1,5 +1,5 @@ use crate::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground}; -use crate::rustc_span::edition::Edition; +use rustc_span::edition::Edition; use std::fs; use std::path::Path; use std::str; diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index f82b89fdd5f98..241dc37ab9cd0 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -594,9 +594,9 @@ fn generate_item_def_id_path( root_path: Option<&str>, original_def_kind: DefKind, ) -> Result<(String, ItemType, Vec), HrefError> { - use crate::rustc_trait_selection::infer::TyCtxtInferExt; - use crate::rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_middle::traits::ObligationCause; + use rustc_trait_selection::infer::TyCtxtInferExt; + use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; let tcx = cx.tcx(); let crate_name = tcx.crate_name(def_id.krate); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 075d94bd33707..b4e62e39d8d6b 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -52,6 +52,7 @@ use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_hir::Mutability; +use rustc_middle::ty::print::PrintTraitRefExt; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::RustcVersion; use rustc_span::{ diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 73c543567c078..4a27ca92fff38 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -239,3 +239,46 @@ window.addEventListener("pageshow", ev => { setTimeout(updateSidebarWidth, 0); } }); + +// Custom elements are used to insert some JS-dependent features into Rustdoc, +// because the [parser] runs the connected callback +// synchronously. It needs to be added synchronously so that nothing below it +// becomes visible until after it's done. Otherwise, you get layout jank. +// +// That's also why this is in storage.js and not main.js. +// +// [parser]: https://html.spec.whatwg.org/multipage/parsing.html +class RustdocSearchElement extends HTMLElement { + constructor() { + super(); + } + connectedCallback() { + const rootPath = getVar("root-path"); + const currentCrate = getVar("current-crate"); + this.innerHTML = ``; + } +} +window.customElements.define("rustdoc-search", RustdocSearchElement); diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 1e01cd70b963f..cdf01fa7a97e8 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -117,30 +117,9 @@

Files

{# #} {# #}
{# #} {% if page.css_class != "src" %}
{% endif %} - {# #} + {# defined in storage.js to avoid duplicating complex UI across every page #} + {# and because the search form only works if JS is enabled anyway #} + {# #}
{{ content|safe }}
{# #} {% if page.css_class != "src" %}
{% endif %}
{# #} diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 4eeaaa2bb70a9..3a71dd82db88b 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -8,6 +8,9 @@ use crate::core::DocContext; mod stripper; pub(crate) use stripper::*; +mod strip_aliased_non_local; +pub(crate) use self::strip_aliased_non_local::STRIP_ALIASED_NON_LOCAL; + mod strip_hidden; pub(crate) use self::strip_hidden::STRIP_HIDDEN; @@ -71,6 +74,7 @@ pub(crate) enum Condition { pub(crate) const PASSES: &[Pass] = &[ CHECK_CUSTOM_CODE_CLASSES, CHECK_DOC_TEST_VISIBILITY, + STRIP_ALIASED_NON_LOCAL, STRIP_HIDDEN, STRIP_PRIVATE, STRIP_PRIV_IMPORTS, @@ -86,6 +90,7 @@ pub(crate) const DEFAULT_PASSES: &[ConditionalPass] = &[ ConditionalPass::always(CHECK_CUSTOM_CODE_CLASSES), ConditionalPass::always(COLLECT_TRAIT_IMPLS), ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY), + ConditionalPass::always(STRIP_ALIASED_NON_LOCAL), ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden), ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate), ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate), diff --git a/src/librustdoc/passes/strip_aliased_non_local.rs b/src/librustdoc/passes/strip_aliased_non_local.rs new file mode 100644 index 0000000000000..848cbd5ed99fc --- /dev/null +++ b/src/librustdoc/passes/strip_aliased_non_local.rs @@ -0,0 +1,57 @@ +use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::Visibility; + +use crate::clean; +use crate::clean::Item; +use crate::core::DocContext; +use crate::fold::{strip_item, DocFolder}; +use crate::passes::Pass; + +pub(crate) const STRIP_ALIASED_NON_LOCAL: Pass = Pass { + name: "strip-aliased-non-local", + run: strip_aliased_non_local, + description: "strips all non-local private aliased items from the output", +}; + +fn strip_aliased_non_local(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate { + let mut stripper = AliasedNonLocalStripper { tcx: cx.tcx }; + stripper.fold_crate(krate) +} + +struct AliasedNonLocalStripper<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> DocFolder for AliasedNonLocalStripper<'tcx> { + fn fold_item(&mut self, i: Item) -> Option { + Some(match *i.kind { + clean::TypeAliasItem(..) => { + let mut stripper = NonLocalStripper { tcx: self.tcx }; + // don't call `fold_item` as that could strip the type-alias it-self + // which we don't want to strip out + stripper.fold_item_recur(i) + } + _ => self.fold_item_recur(i), + }) + } +} + +struct NonLocalStripper<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> DocFolder for NonLocalStripper<'tcx> { + fn fold_item(&mut self, i: Item) -> Option { + // If not local, we want to respect the original visibility of + // the field and not the one given by the user for the currrent crate. + // + // FIXME(#125009): Not-local should probably consider same Cargo workspace + if !i.def_id().map_or(true, |did| did.is_local()) { + if i.visibility(self.tcx) != Some(Visibility::Public) || i.is_doc_hidden() { + return Some(strip_item(i)); + } + } + + Some(self.fold_item_recur(i)) + } +} diff --git a/src/stage0 b/src/stage0 new file mode 100644 index 0000000000000..5ec8f5b715e07 --- /dev/null +++ b/src/stage0 @@ -0,0 +1,447 @@ +dist_server=https://static.rust-lang.org +artifacts_server=https://ci-artifacts.rust-lang.org/rustc-builds +artifacts_with_llvm_assertions_server=https://ci-artifacts.rust-lang.org/rustc-builds-alt +git_merge_commit_email=bors@rust-lang.org +git_repository=rust-lang/rust +nightly_branch=master + +# The configuration above this comment is editable, and can be changed +# by forks of the repository if they have alternate values. +# +# The section below is generated by `./x.py run src/tools/bump-stage0`, +# run that command again to update the bootstrap compiler. +# +# All changes below this comment will be overridden the next time the +# tool is executed. + +compiler_date=2024-04-29 +compiler_version=beta +rustfmt_date=2024-04-29 +rustfmt_version=nightly + +dist/2024-04-29/cargo-beta-aarch64-apple-darwin.tar.gz=5a8c5e48a88e7c7b41eb720d60fbd2e879b97639c7ff83710526e8e6caaf8afb +dist/2024-04-29/cargo-beta-aarch64-apple-darwin.tar.xz=0d237535ae8d435d99104fa5b9dbf41878e2304bb0f2eb574bf17dd685caadc2 +dist/2024-04-29/cargo-beta-aarch64-pc-windows-msvc.tar.gz=c56733bb6198af0a9b0df9a44ef979150e00de33b70853c239cccfcce23c328f +dist/2024-04-29/cargo-beta-aarch64-pc-windows-msvc.tar.xz=7da5f887151215ddec640684077d98551fe2aed75a3ece2c73b20698754a70bb +dist/2024-04-29/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=73851e304a539d41bedc0d8a5d98800c8279ae623d3e58e863f8c1f8b458b01c +dist/2024-04-29/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=db9c28841344b0154756e19a21795ef6e0c4e27c7844be9996824f1039edaa81 +dist/2024-04-29/cargo-beta-aarch64-unknown-linux-musl.tar.gz=a706c8c7e37b9e80d7faa000c5d179a772746eef071387fb2879fdeab1f1f891 +dist/2024-04-29/cargo-beta-aarch64-unknown-linux-musl.tar.xz=2060634afe1b4a19bae874c6ce3cf4256e613af26e06104b45da5bd71cfb133c +dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=7af61e74faea669fdd41793e4b88eb6a37bfacf845af364ee02bb7cf08c612c7 +dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=4759fb3e3d89ead605c4eeba23be5cb9b3ac98086a9de20f8dbfdfa9282ee486 +dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=4cab18df2d94702e8b551357373bcae60d1023e644148f0f82e8971023362121 +dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=7de4f0d72b4e5770376ede82b02d6bcfd450788a40375fad34d75524c941d72c +dist/2024-04-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=6401391a426cf33d6c58f07e7b2828b178720cb4f2b8577ae932b5f5b7d6744e +dist/2024-04-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=c3f6729bc769325046f0f62c51b5bed30068c37dc2a36a6283e50565d8cb7d5c +dist/2024-04-29/cargo-beta-i686-pc-windows-gnu.tar.gz=d116c97c1242220c7972b63010aee1ed36bf5353e84a06d3561cd5fe9d7dae84 +dist/2024-04-29/cargo-beta-i686-pc-windows-gnu.tar.xz=65eba577f7775b3eef36e7f000b5007264392b20a7759f8ed567f3a45b2877db +dist/2024-04-29/cargo-beta-i686-pc-windows-msvc.tar.gz=d418a3371b3631328bde2b1e0c3159700f12424e83b1d8ece1349fea90f9e403 +dist/2024-04-29/cargo-beta-i686-pc-windows-msvc.tar.xz=23ae73c776fdb0795944656d743444e3b4c440f45084028206c1aec52333b1ba +dist/2024-04-29/cargo-beta-i686-unknown-linux-gnu.tar.gz=b6bbdeb7c8bfac2e8a083adb4782caf5321799f47acb4eaf81da32bd11730e9c +dist/2024-04-29/cargo-beta-i686-unknown-linux-gnu.tar.xz=6b409691da6ddb8c04409667b2c3d9d6429c6b5bf53ad18177248406a5f06cb9 +dist/2024-04-29/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=24cd888d14a788e8fb5b886735f3c07a028a8681df48a777b2bb971c62a175ae +dist/2024-04-29/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=e8eece6412936fe4dc863a5e19e6766fbb20e81da0069ad7831465e638db23da +dist/2024-04-29/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=8f007a2aa02e35c5ddb2152cc7589092a0e3083211c6aa23e676e3a3ad5a4b8d +dist/2024-04-29/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=3e423e693dd0813f5d87d9eded94894076258ece56684f3598321cd013aeef3c +dist/2024-04-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=2eec5e45e389a52b526a5cf683d56a9df92004f6095936b16cd8d7d63722cc6c +dist/2024-04-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=64c5135cbff9d4fa9575074c55e79d85f72cb1783498a72e1f77865b9b2d1ba3 +dist/2024-04-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=d64552a80ca386728e42f00d7f1c700b5e30e5a6939f32ffa15a7ce715d4c8e9 +dist/2024-04-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=fe91adce8ba35bf06251448b5214ed112556dc8814de92e66bc5dc51193c442f +dist/2024-04-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=77aafa8b63a4bf4475e82cd777646be5254e1f62d44b2a8fbd40066fdd7020d3 +dist/2024-04-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=c38f0b4adcc8e48f70b475636bbd5851406bba296d66df12e1ba54888a4bf21a +dist/2024-04-29/cargo-beta-s390x-unknown-linux-gnu.tar.gz=c05df24d7e8dff26c01055ad40f9e81e6fcb3ae634ecc1f7cc43c3108677fa0e +dist/2024-04-29/cargo-beta-s390x-unknown-linux-gnu.tar.xz=47e8f4ec4d996600e60ddc49daeeb43d4c21e0583a86c12395c16eddc7db76ee +dist/2024-04-29/cargo-beta-x86_64-apple-darwin.tar.gz=f024bd225b77160dc2fabde78002c8deac5cbb9a35345340964c3b988b0d1791 +dist/2024-04-29/cargo-beta-x86_64-apple-darwin.tar.xz=96c9e44bd9f0c85c793e3dd6043cc4f89fbeeab5ddf0fdb5daefca8f690bce05 +dist/2024-04-29/cargo-beta-x86_64-pc-windows-gnu.tar.gz=517889f222b62150fe16bcfd3a0eb5f353956b0084d85713480197bff4558145 +dist/2024-04-29/cargo-beta-x86_64-pc-windows-gnu.tar.xz=a6653ea4aec51569c1300c044d8bf2517a1f5111f710d12cd352190425b8f317 +dist/2024-04-29/cargo-beta-x86_64-pc-windows-msvc.tar.gz=4cb5b5054dffe6721efbbf29192a67e59cda69ea4ab4791aaec6f314eefa5a5e +dist/2024-04-29/cargo-beta-x86_64-pc-windows-msvc.tar.xz=08bc45be22e9e4f615d1c9e70500046c8db89045f5d40dcde853c610591712a7 +dist/2024-04-29/cargo-beta-x86_64-unknown-freebsd.tar.gz=9661357ee8ea8973016fdbaa2de3cb98713136dcd25f07aa9f9d101180276815 +dist/2024-04-29/cargo-beta-x86_64-unknown-freebsd.tar.xz=7fab806227d1a3be817602abb121ac7e039ba0bbf81e0a1d47bdcccca74203c6 +dist/2024-04-29/cargo-beta-x86_64-unknown-illumos.tar.gz=4c79bb48cfe64bd38af7fe3660cd8bdc99ec90738a0d8fdf80843ecda910dab0 +dist/2024-04-29/cargo-beta-x86_64-unknown-illumos.tar.xz=0fb9edfdafde1820ccb25c22369cafb0e75e68795effeb615cb284a5837c75ba +dist/2024-04-29/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=c1902a072e61ab5ae9737a1092732e3972deee426424bc85fcf8702adffdd41d +dist/2024-04-29/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=d39ea1195dcc95e428bd540abd2db5b5d4c997a7661a41a4c0ca41cbdd18d27e +dist/2024-04-29/cargo-beta-x86_64-unknown-linux-musl.tar.gz=0edfdb6f6bb2a4a1a96a5e95cec897c444c936e6624bb4a530ffed4847b97445 +dist/2024-04-29/cargo-beta-x86_64-unknown-linux-musl.tar.xz=70c264b7845febdee45d0c6e44b65d47ba7f367ef33ec906a9fd7f992ba7cc13 +dist/2024-04-29/cargo-beta-x86_64-unknown-netbsd.tar.gz=f1bd6417a54f3b53d572ce4af799242db7c11265c71201cc09c78d71be38c13a +dist/2024-04-29/cargo-beta-x86_64-unknown-netbsd.tar.xz=53569810469c483785333759f86434706ee5368d5e18270ee13a17817ad57d40 +dist/2024-04-29/clippy-beta-aarch64-apple-darwin.tar.gz=7b693bde61a090854527a145455ff774314c65ec0cd47d25a19c76c6a166d96c +dist/2024-04-29/clippy-beta-aarch64-apple-darwin.tar.xz=2494e9fdd8d342b6bc3e55eecfd555c43e3cca8421f3236df2d5a366288fec62 +dist/2024-04-29/clippy-beta-aarch64-pc-windows-msvc.tar.gz=90307f09c6fcb0c1fbe3ad1522a5381a17e2f69637c6d00f4a2cb5f3149bf736 +dist/2024-04-29/clippy-beta-aarch64-pc-windows-msvc.tar.xz=f7e0dec4a4862bd85d894252366152b3b6a7627e7e5a25ce323fa2db3bd87c2b +dist/2024-04-29/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=7c719e38f2a1030ae61985205df52f9a0c37b659463a5e2dea8e60e632de2d73 +dist/2024-04-29/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=181ff4ae6adced6522a4c29869be3cc5dac8b961c7c88f2957cd31f831490807 +dist/2024-04-29/clippy-beta-aarch64-unknown-linux-musl.tar.gz=4e0e63e6f200386995e369a2673867d1bc3005d51d6a57c00ca80056dd85316b +dist/2024-04-29/clippy-beta-aarch64-unknown-linux-musl.tar.xz=3d5b22a13aed6821482e60d9cc8571e2da9d95d82104284b77c56985a35a9c4e +dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=9f788db76a5d55b3ecdd04a70b0e2be466959f76ae9fd3497ca2c503504e0c03 +dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=f4d8fc103807fba61d71d88b8e25a7016bfbd1a2905330f9a9fb3d7ba082713a +dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=d61bec3d017dd0be43e48350190ad18c0a0269e43d964600b62e1f7fd4f84399 +dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=c00cbdc41a4da0c313a1a282b0158b059dd34f640b582cb7ca18e3d290ca8fa5 +dist/2024-04-29/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=52143a530ca5274fbb760beecddff16f860ea787443d3dc708dda7c8f32ca9bd +dist/2024-04-29/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=c6d2dfeac6f40811bc9b4cec3c23f9c3bb46f761e006257b9313aa7c1a647b5a +dist/2024-04-29/clippy-beta-i686-pc-windows-gnu.tar.gz=325d39e426b1907fa17d93c0752d3d73bd95750f4f967c2a84aab2c5dac8a588 +dist/2024-04-29/clippy-beta-i686-pc-windows-gnu.tar.xz=536f591d4da455302029384ed196932d71119ef0160ac5415617d6b777c51123 +dist/2024-04-29/clippy-beta-i686-pc-windows-msvc.tar.gz=c3684c9bf471669d444853bf484880d17e150ecb0e7505de90883382023e343b +dist/2024-04-29/clippy-beta-i686-pc-windows-msvc.tar.xz=0b00e6132f73d5dc762e359b0005fceab0cf7b01337d8f4aa9eacfb4552f9245 +dist/2024-04-29/clippy-beta-i686-unknown-linux-gnu.tar.gz=c91c1eadfc4cbae360a0eecf11c32d2509b68aca86c7b1de3b102944f43e1511 +dist/2024-04-29/clippy-beta-i686-unknown-linux-gnu.tar.xz=6f7a5a287dd6226c203bb674ff02ec773e5d0813091b2af744b88ecd6997a304 +dist/2024-04-29/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=58383f094995823ea6db6a87b9ad4b33bdae2264d29bab88ab71ec60ccab3b93 +dist/2024-04-29/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=dbf4680a6fd4dca54acca5503a7fd94502b8e85819bc02346ae9cecd275e4514 +dist/2024-04-29/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=e28eb32cda42654c0f0247aa8e15f01f73770b36f7626c8d6f1b7659accc56e6 +dist/2024-04-29/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=fcc48a83b748e1e46f9daef40563f8e5abbb0e3f014a168b04f3c700c2ace2b8 +dist/2024-04-29/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=b626faf3275fcd196cd627e8a36c67721bae16a56f61cd080c79d137b3ec7737 +dist/2024-04-29/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=2c599d2dc719d69f67625f3c6573fcc4f1ea3266801557dd3892bdb7c761b4cf +dist/2024-04-29/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=0bc1f546fe0cef2b9516231ab608de68d55f72022fbc9ced5101b600e005f8c4 +dist/2024-04-29/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=993294f2ae5202785ab242c1c6567df9c8ab1ef44ad35748c526b7fe854fb94e +dist/2024-04-29/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=210a4f0d208e0c8e13a57fb3b3e6c98ab5f620e4988d10a127ff1424ac1d5ca9 +dist/2024-04-29/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=f10f7df41a13ee2ecdc25d60e697cba2342129a912ef20d8bfca5f611a9ec97f +dist/2024-04-29/clippy-beta-s390x-unknown-linux-gnu.tar.gz=3e24d2af65f0c9667c9997ce091711b2be48e673de3707cddfd8cda455dfecc7 +dist/2024-04-29/clippy-beta-s390x-unknown-linux-gnu.tar.xz=0e7b8fbd0207489e38c78c2ae1aa0df4fcbdd84741aa50a86379e4d7ede286b1 +dist/2024-04-29/clippy-beta-x86_64-apple-darwin.tar.gz=9c0c47fd97ce72abcd6126315834c62aa7297fe09d447ee4cefa1eb46a116326 +dist/2024-04-29/clippy-beta-x86_64-apple-darwin.tar.xz=49dd65c5340fd804399edfa2402cf255fd9bfce1f4aa7fbb3c193c11bc03f8af +dist/2024-04-29/clippy-beta-x86_64-pc-windows-gnu.tar.gz=6c1c3bdf097a1846ae08b098c555c0c5e9e9b646c744d6bb5a855789196b8bf6 +dist/2024-04-29/clippy-beta-x86_64-pc-windows-gnu.tar.xz=0a7319d1062f73af1c8f0efe6ad970d10d02259162c5bc84bb1f3a10f3911bcb +dist/2024-04-29/clippy-beta-x86_64-pc-windows-msvc.tar.gz=52fef3f8a64fa58934a633bd4944e8ba9e15f2c2766d0f302dea1a6523864dab +dist/2024-04-29/clippy-beta-x86_64-pc-windows-msvc.tar.xz=8fdbe7590e62ab68a2e463b14da2595e8c4592744f578a813f64d430ed7db4b6 +dist/2024-04-29/clippy-beta-x86_64-unknown-freebsd.tar.gz=509bf535622bd26385184ee0c17e4e27a5061a8aeebf5759f24bd578692b2f5d +dist/2024-04-29/clippy-beta-x86_64-unknown-freebsd.tar.xz=2fcd10ada329ba7633616bebc584dca13f11c465e7cf513e76efeb0c3174486f +dist/2024-04-29/clippy-beta-x86_64-unknown-illumos.tar.gz=ea8cea0d4a2379bcd0693f6174b25bc1f90a016dbe8280159cbb61d859806fb0 +dist/2024-04-29/clippy-beta-x86_64-unknown-illumos.tar.xz=5a243df8d1345db6bd18e4386ba628e6d302bce1cc572fb447cca4264fda3ee9 +dist/2024-04-29/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=2ee560d3c1e306e103eb06d8e8033cd1489b3f6ff9df3bd8a95e25e977befa27 +dist/2024-04-29/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=aaf6e54184a65ad6592bf03955a84ad12b561afd86064b1ac5fa03cf637052f8 +dist/2024-04-29/clippy-beta-x86_64-unknown-linux-musl.tar.gz=1b3877424a0a0eb507675a50e9d2c793f00ab85f6f12b1e27f871331070325b8 +dist/2024-04-29/clippy-beta-x86_64-unknown-linux-musl.tar.xz=6df5eaae5afb64557ba5c3a53ee3e56dab85455838a6044c7671c1180acfeaf9 +dist/2024-04-29/clippy-beta-x86_64-unknown-netbsd.tar.gz=1ac05ed7b607fff8b77ff203a663e9f4f2487779bc25e2dcd454cdf5b7583328 +dist/2024-04-29/clippy-beta-x86_64-unknown-netbsd.tar.xz=da502375b3cee8b254ab5999809f522692c2d1d90ea0544ad03c0ca514c65ef4 +dist/2024-04-29/rust-std-beta-aarch64-apple-darwin.tar.gz=2fdd35ca3b3e3d6f548f11c93337f5bf2e3c088bc78a79881e6f8e230b38b9a5 +dist/2024-04-29/rust-std-beta-aarch64-apple-darwin.tar.xz=bc16b3a1ab6ed69f0121a117c50cbcd201500dae4d72ad0dab148913d04cc529 +dist/2024-04-29/rust-std-beta-aarch64-apple-ios-sim.tar.gz=9375c786703c17baae1c2066f8d972ac316bc840e478ecd1b94288a1d428324e +dist/2024-04-29/rust-std-beta-aarch64-apple-ios-sim.tar.xz=50d6818a8dd3ab7a3ddbbd7a062b538d9ff3ceb6eada031d1c22ab1dc7ba512c +dist/2024-04-29/rust-std-beta-aarch64-apple-ios.tar.gz=56c3a01e8fd5c2ed75df811993b0b724709fb5473cc308ac09e7f5644468f751 +dist/2024-04-29/rust-std-beta-aarch64-apple-ios.tar.xz=3527d1f2c99c806479fb4b3801335dc921b514f171b82cd252cbbfc9ed30b163 +dist/2024-04-29/rust-std-beta-aarch64-linux-android.tar.gz=bf8cae7c66489f1aa27f1dea1b37f0d0ae514a6e21b93ff2dc6400dc88feca03 +dist/2024-04-29/rust-std-beta-aarch64-linux-android.tar.xz=46799f0bc1b3c13877f6cb732774cb3b33e0d8a081bfb56d0f877e79482aa1de +dist/2024-04-29/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=9f90fadab5104e1d415edf3b4edfaf7222f9f0d55f849851efdec74ffee16f8d +dist/2024-04-29/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=87ed6774202b18691bd6884df6944c7e9fe9c944b57a2837e7a7647518bf94e8 +dist/2024-04-29/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=4a0692ad28f7f130b472ffa4aa766b745ba01fb75aa921f2da6622c9c68750df +dist/2024-04-29/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=a3d45962489a1e18a87e567cbbc8d3665f38809d0ad2ef15bcf0ff9fb9f470a4 +dist/2024-04-29/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=c724f4eb135f73b9c79618f27a1ab35dc7b9d26ca62ed796accce68f9e747a66 +dist/2024-04-29/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=8eab25782d16bcee75f86ecbb826346beb4a7525b220b45b3ba05a567c6d4391 +dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=33ab1f8410edf590570d7468dbe2ebb5a0907125bbc8d360a928dcb355f0d0e6 +dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=d3d870209a55ac96391affaa347c04f48cf98c089ac5056f340b8bb38bcc8e60 +dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=4d2bb72b898c30a2fc8d5d3333c2e99a8e30c15891fab641b6a519dc9f0cb611 +dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=fa343e6b6110fcd0c5dae4287ff1a799de5d7e4a805dbf4e9a034bbaed2bf269 +dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=f1ec4139783169fd83e1b0184518ed25d26cee7b21f196deecc74e83a1d78725 +dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=d100be2f6f0346c4b1f5b41aec0c13a47426bf4d49127f2341c8332903e4e782 +dist/2024-04-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=bab6051e1071a58cd126580f6644decf16edb4473fe4be6a34791610d820a294 +dist/2024-04-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=d9b68f06ff23629063e92dfc42aa3115a858238d368e4b52b35c1ea4491b1402 +dist/2024-04-29/rust-std-beta-aarch64-unknown-none.tar.gz=96804c2d9accd3242bdc22dad688b2ccee071952477b9c592f099377aee6c591 +dist/2024-04-29/rust-std-beta-aarch64-unknown-none.tar.xz=3fed6812d84bdaf787e85c37e23ba729b81a6d25a2b33fed75320e66e6641c89 +dist/2024-04-29/rust-std-beta-aarch64-unknown-uefi.tar.gz=8da5f301bff35fc067ec7cfb878ebfa5607af7dbc276a6b34a77404432c700d2 +dist/2024-04-29/rust-std-beta-aarch64-unknown-uefi.tar.xz=80d643189dc9af98b6410a01261ce6ad34b1325f3aebf3ff61fb43f1261b41ff +dist/2024-04-29/rust-std-beta-arm-linux-androideabi.tar.gz=2e86b54b0d1f7fefead11d6383bdc80fe0a7b3ccf58381d2a731e6f1c62926de +dist/2024-04-29/rust-std-beta-arm-linux-androideabi.tar.xz=9831a0270457cad2798b5ae4fe956c257c7e10ce5ad211793dc467577cdec29e +dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=f96bc303c0c2be9cf589f00aa63b2cf3fb8585ca9dd8860fe525821bfa1fe19a +dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=e57a053b1c2bb6fad93dfaffedce7f48fa292196fc8ba6fd2f0c74dc810a13a9 +dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=49b2cb2ba5296871b5fac5ad9a74a2891e8b78321078a455ba4a65e003bebd40 +dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=0f9c15d834a9d282a4018934759f7b48ef3d275e09679a68c5fd1b3f047d02e4 +dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=e59f92827241e670c1aa92b35235ad12340869d59327fb83084b5f4149acbe06 +dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=ad1cf96bb1fcceaa016e29e8ad34b4cfd711d2e0bd7cabb9cd7cc28abf64d894 +dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=14a6d318af85bb9fa5c229e45a88a32a71f44ed02cd90a24bb67921eb64dee41 +dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=ed6b48502ab9169818bceb300b4e6b4fd63366ad5808b047bf9988dae04c2729 +dist/2024-04-29/rust-std-beta-armebv7r-none-eabi.tar.gz=345e8a023be55e3b88a0c2677ea28c7bb4fcc5f3ab707638de76065c7592c2d5 +dist/2024-04-29/rust-std-beta-armebv7r-none-eabi.tar.xz=6d9b11d08f2d62611327a893b45ba07c36df11f077250496ab0881eb7ac84c65 +dist/2024-04-29/rust-std-beta-armebv7r-none-eabihf.tar.gz=a2ae1bf003a8a12b2ecb6bde9868a978820f184af523f0e4c3fc935edd509423 +dist/2024-04-29/rust-std-beta-armebv7r-none-eabihf.tar.xz=3d1dcf8308f9d4590b429f6abbf8f42f04496ab490ccf4ed8c9e381e6d886cae +dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=a54106d27e4ce97463e7867ceff9dd22ba456f840ec23229e6909b37d48ad554 +dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=e6abfaa0905a00efeaee85b9f93793bab93e2cf4e172c9d829c5ba85006c688a +dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=cbed18e5dc61fcecb2920affc3890c3b8ae46b7fe5a80b3288689e18d490f3f4 +dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=2b58bb0dd5cd2c5f7f93f4c6e9135090b931e0ffa27ff9efe2b8ff9fbbb7e48c +dist/2024-04-29/rust-std-beta-armv7-linux-androideabi.tar.gz=6a371c2ececd349dfa76a02563069912fc91577ac4446d36c22f96723d7f5e9f +dist/2024-04-29/rust-std-beta-armv7-linux-androideabi.tar.xz=9325daf41ddab02fa845971c10a5e0538a18c7bea14e66fa0f5f6fb16654c7ae +dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=7f5ba76cfb7c85333c8dab76fb4ad3f12ddc254b95f9ee07fadb8e1270a4f767 +dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=f853b7f929b7a309ed6c08ff8c57d583ce0ccb19270674fb30e63a873834dc87 +dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=0680005d0a12498b687afc583d4f36bd67d0877cd9d3323bfd2df50d15c27afe +dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=a494b78fcad01c83df9522d460ac2d35d2d00736a921381f2c611dc516edaa16 +dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=cfa555db31b5470e878b0f53d86617e7342e8bf018fe62cb0271dfe13db95f51 +dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=0a8ccd6d88cbe79a855111fbda45aa1a728de655b6927f3d429d901d2afc6503 +dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=eac53424001c884a540c42f0b68447349ec5d0601a030c060aaed76d54895728 +dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=42d78fca62361ff28db5bc43bb01cef7af5c6f4ab2110fe6170c3dce4707aab8 +dist/2024-04-29/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=c88de9f2e667da73177fb9c9309d7f1f467e31c18e3ae50d722c71ec8dd876a4 +dist/2024-04-29/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=24b3c04a42d511cdc8c6107b597be38981114f0574eced493d0e90fc748094bc +dist/2024-04-29/rust-std-beta-armv7a-none-eabi.tar.gz=cd4ad182a098c61550265879ccc04733c39110827f7ef62eecfb8c120ae4ece8 +dist/2024-04-29/rust-std-beta-armv7a-none-eabi.tar.xz=8499a014dfdf448f474a58f148784c2eef245dc909587d876d2fb9ddc6a4ec3f +dist/2024-04-29/rust-std-beta-armv7r-none-eabi.tar.gz=e8e1870e5b12b3d8643d712efb91eb86b2081284cada4a140c1526692ab183c4 +dist/2024-04-29/rust-std-beta-armv7r-none-eabi.tar.xz=d6029121eacc44bd4dcd9ef6dd3cd0d775cb6e9a3d99f3d62d746fcbf8981cab +dist/2024-04-29/rust-std-beta-armv7r-none-eabihf.tar.gz=1e0fc42c3802e205130c01ca90f92d793c1c5427b34da66fe77b97cf67b4a5c1 +dist/2024-04-29/rust-std-beta-armv7r-none-eabihf.tar.xz=4c8cfdb11bb686111fa4842d13430c86d9d14ada30e9df334b3777fe899233e0 +dist/2024-04-29/rust-std-beta-i586-pc-windows-msvc.tar.gz=ff895c1b39b84587f10903f4be13d275b545e690da6761190d12c01acc25c6d8 +dist/2024-04-29/rust-std-beta-i586-pc-windows-msvc.tar.xz=fdcbcff7b740235bb16e44174fff9080a7c0a31be358c8abc41805c02c20c3b2 +dist/2024-04-29/rust-std-beta-i586-unknown-linux-gnu.tar.gz=6b227f3b9001e148b66b7001f753a6f88fef9677e39d8fcf4d9c35fe8d345568 +dist/2024-04-29/rust-std-beta-i586-unknown-linux-gnu.tar.xz=1e29297beb8de3778ba958731294823d9a93aac1e0d8833abc5aa99e2935965b +dist/2024-04-29/rust-std-beta-i586-unknown-linux-musl.tar.gz=26481ad5f22a319830d42f69b1c0195bd65900ebe112e659432334b3468f3d0e +dist/2024-04-29/rust-std-beta-i586-unknown-linux-musl.tar.xz=c8a837e0d9da8ad976fc1539541c085365aac9dd28b34e4a289d38a823d1b065 +dist/2024-04-29/rust-std-beta-i686-linux-android.tar.gz=f05e28a52f17e22f36ffc70018012a1fe6a07f4b461e774b36464f32bc8f8dea +dist/2024-04-29/rust-std-beta-i686-linux-android.tar.xz=f9501b2691c51e54a6f4cc6fb72e41901eb551d3a7be5f82a94ce2d3e217828b +dist/2024-04-29/rust-std-beta-i686-pc-windows-gnu.tar.gz=8d9a782d4f7450bca536aab45147c6ef08bc3847b43fdd171c6449e29762eda0 +dist/2024-04-29/rust-std-beta-i686-pc-windows-gnu.tar.xz=4008712e03fb6494eaba3d79051c5e3fdd93d4c52ae8d86cf8f344b5f051cbca +dist/2024-04-29/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=cfb23242e495834a3d0f7ffa3da4a0b206dcae35872b1455b11faeee5511ba5f +dist/2024-04-29/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=95415742c0171945ffc2b67c913ebd1330e29634af238f5ccc843a965340374a +dist/2024-04-29/rust-std-beta-i686-pc-windows-msvc.tar.gz=e9354d69e39ecfac1d2928664d17d73f808256a4076b849171a9667705c0aa08 +dist/2024-04-29/rust-std-beta-i686-pc-windows-msvc.tar.xz=a34bb0a91170d84195f35ba52afa4c9be8a2f2706dbeea02bd6e8908e08ac65e +dist/2024-04-29/rust-std-beta-i686-unknown-freebsd.tar.gz=d65f286de399ccc9e9acaf7a4dc4f885357c750231d54a144ba9a59181814f11 +dist/2024-04-29/rust-std-beta-i686-unknown-freebsd.tar.xz=4c93a7da70a69b2ebbac01df64af16344e523d16470b29e57237b1d0925f7721 +dist/2024-04-29/rust-std-beta-i686-unknown-linux-gnu.tar.gz=1b978bfd1a9234be7ef197c8c98c5a6b625f6fbb7b0fca58695986768bdca176 +dist/2024-04-29/rust-std-beta-i686-unknown-linux-gnu.tar.xz=98d4eb5b89a593c8c4f86244c9a7c737d9c18c0168aebe5923b8d9145adcf89a +dist/2024-04-29/rust-std-beta-i686-unknown-linux-musl.tar.gz=dbf9b3c5b54b3eb0727f976f5632c5b0fcb2f90ac7453962d6cef20f7dae4284 +dist/2024-04-29/rust-std-beta-i686-unknown-linux-musl.tar.xz=f209ade093753342dda6e710ee832a538dbdaa08a24d606f9a2a1bc59b83da29 +dist/2024-04-29/rust-std-beta-i686-unknown-uefi.tar.gz=3c3ca7f34569b2c70c6b223754418a535dd7dfa087ab6e28ed2ec78d20065887 +dist/2024-04-29/rust-std-beta-i686-unknown-uefi.tar.xz=72a7cd0f430ab40d80e93f409b8e26a181010ab4bb75d151e829d51ccdcf8c62 +dist/2024-04-29/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=b7dfa59bb05cf806c87854d6fce5ef0f160697052fdf6e5a0cad121499108608 +dist/2024-04-29/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=88bc22f68bab3367cdfa91676418ce1ffc0ec002afb32aed7def880bdd4be402 +dist/2024-04-29/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=d61019048b941064a99d19e46ff3236a88a2e8fcfb963cedd1d9d1c47963c170 +dist/2024-04-29/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=7474bda08134c676d74afe5263317af3f271963d8ceaa5efbfa1b657f885c572 +dist/2024-04-29/rust-std-beta-loongarch64-unknown-none.tar.gz=e089c77d433d838ca02d7531d6f4a1770fb4a0568acbd96c8f43034d76f2990b +dist/2024-04-29/rust-std-beta-loongarch64-unknown-none.tar.xz=364ae6c89c7a930098286e55193d2f5ee3d5ea80b7cca73046e41725f4a8a2f9 +dist/2024-04-29/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=c17bfad87d16f3a8d26646525dc59a352718db9e7572acb583b68a18cfdc338a +dist/2024-04-29/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=f5c4ecef1c08d19ba6fddbd359a0ce94e46888021cae057fce969276026d086c +dist/2024-04-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=3e7e13b0d2e804d228e1e3a9dac0205d294ae29dcc37132f15fb1e218861eb39 +dist/2024-04-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=ea31b7678e6f64c2f9c28a9af120be04ed6f2a25a496e40afbf6e9aa0dd20b60 +dist/2024-04-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=f0e1b314c3d5ad1676c68c112581dce62fa06ad557cd5f61034e147b064ed270 +dist/2024-04-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=8ab7bbea6e2f72df1286facc7d306d01809a4dd9f8901dfdec7e50b594658d49 +dist/2024-04-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=48f6abda1c7dac185858744aa2cdc3513cdfb6552535282ee83cf9c5365573c7 +dist/2024-04-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=d920d97f15b56ba6ea81e08b3c29dc7f44f5f30b7513c53446edf95843c332af +dist/2024-04-29/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=0a198a770f6e6043e923b0ab1a508fd8b190612d0370c33c8dd2c5f63b6f19dd +dist/2024-04-29/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=424a93313cfe2d85acf956be3d9ac71ea8e34ee61617a550ad6ff5360e1dff52 +dist/2024-04-29/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=2e2b0a8e41f4ea774d665d6248cbc2fdbe3e582206efeb87d250786ebaad0b1a +dist/2024-04-29/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=2da372c091017b7096e473e5c7016a504d2e041e14173d2520086cb43e0a615a +dist/2024-04-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=69d3b21403181b2df14243816388169db2466477ec34bcca5693fb017703686c +dist/2024-04-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=281b9c20f8641a3d1b349e762b7f713fb0b91da0d21eec798e639e36a0ea3dab +dist/2024-04-29/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=dd9bfd3fd8446d35180fe781139dfb4e04dd658b112eb2a749e8f4aea14f0271 +dist/2024-04-29/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=b1366375e0c5f53da581741dec91972b0c46d7d466052539207e8feaab0ba3ec +dist/2024-04-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=7c6650d8cf8abd51547010e8211af3ef3195099ef43a563460ad4780de20ba17 +dist/2024-04-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=bab46f3c0078ce346de563bb7a248ca92f15dbdc73bf5a3bc520486118442320 +dist/2024-04-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=01735b4ad5bc0a53087dd0ccaef2cf174b27e45bf4d2e3c15e64f7522f059c63 +dist/2024-04-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=0bb272c2c235583ed3e9ec151b3bfc601f8cd07822c2fe47a1258b358be507f0 +dist/2024-04-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=b2c7f8ee0efe6d0812e4b5dd0979f60f105b84d34d4f600ef75f2eacd954893d +dist/2024-04-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=0d5301fc553a6911af6643ab7f57b6438bf649ffcd050d486278c0c5fe38eeba +dist/2024-04-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=0d1d35ecb88ee717720ad8e74bd5b602fd6011fe321baddb939f3b161e9cd8c5 +dist/2024-04-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=a5cf0b98596e68e6f72be2e83c61b8aaa19ead42f248ee2408a3b8f4e97a6657 +dist/2024-04-29/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=629ed749cdae110668ad9ddbc5c61e99e8d400f3dd0981146c3820deadc360f6 +dist/2024-04-29/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=192819438ed27a565cdb67b51d2f5caeb6ae258de86191d6922574327f132acd +dist/2024-04-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=84286f6cf6f00f3c92dc881f64a31e1ec5910102d8d3d4faf6fc7e2ddf1544a7 +dist/2024-04-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=304b5f876b47dcbb7c3483c49295b822e8ba83234bb568ce67896ae4773ae2fa +dist/2024-04-29/rust-std-beta-sparcv9-sun-solaris.tar.gz=25062159b859e21dda76ca22d4a31d3aba4fcdb0def78bc5b5cf9887c07c1be9 +dist/2024-04-29/rust-std-beta-sparcv9-sun-solaris.tar.xz=5d557ee86457f288462603fe53bcc2e092d84faee543659419fa68c1bd88f554 +dist/2024-04-29/rust-std-beta-thumbv6m-none-eabi.tar.gz=a9663048aad82ef832b2cf82fa9fb94be047f77e283e8aa3e2df6ad957d0782d +dist/2024-04-29/rust-std-beta-thumbv6m-none-eabi.tar.xz=4c4b703a846b4123d09c1eace6322e82784a004b278f1f3b1ca1279e96207f18 +dist/2024-04-29/rust-std-beta-thumbv7em-none-eabi.tar.gz=32907c33f240abb1cb17ac438da42c5fa3932b270ad08fd6914775c5b59a02f5 +dist/2024-04-29/rust-std-beta-thumbv7em-none-eabi.tar.xz=112583227d2b6abfef6eeb78d980bf2efef392f3b66e433c4959a642d72ffc7b +dist/2024-04-29/rust-std-beta-thumbv7em-none-eabihf.tar.gz=7ba0084527a18479c4b6f6a0dba8ae23a0ed50e9fc5fbfce23cae1babb5a1e12 +dist/2024-04-29/rust-std-beta-thumbv7em-none-eabihf.tar.xz=49eb4e2efe3a76713ce1fecacaf915717eeed8552912b92895c7fee068a85a36 +dist/2024-04-29/rust-std-beta-thumbv7m-none-eabi.tar.gz=518a532b52f2dad2825158614cd00b12aac6c6e1983a1ad53e2b0e26d1f1b845 +dist/2024-04-29/rust-std-beta-thumbv7m-none-eabi.tar.xz=2895e5796a29fd016462694d880e38eb191cb92c9bdb14414c1d6e63b23d3394 +dist/2024-04-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=2af590c063344c4c3f65d704fa255232b5f5954872d03c4c55d48662cbe6bb17 +dist/2024-04-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=a09df5f38183d9fe6116c807619f812410763ddedf06055bfe8040b5794104d3 +dist/2024-04-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=eac22c4972bde3a57cf2ec4e31b43db3c4b7d961ae31475d8942e898c07640cc +dist/2024-04-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=104f2c6490e30cc47833edbd806c2efe6256d1194600b2278339612f94704d45 +dist/2024-04-29/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=b3c9c9d7ce8c1db6f20e8ede542e67aacd6047c52882a5d06c4f96a40a7304d9 +dist/2024-04-29/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=76bfb114bc7674792934a4892d2db41fdc8f5bd30c3aa96c43e8055199157476 +dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=1308335fe80dcafaba511ee589959d461145533de5f76118fee29a7e9a15841f +dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=cb8acdb8920983c03b9495cf3506a3014384b4d2f6a53e7907924d38a0baf7f0 +dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=9dd2e5ce7534ab4fbb93ff652196e877f4e9eea3863920c3d34a05d9a3598c81 +dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=4b6e962facf7c54846965a8d6880e4a980804459151f2e22ac5af79bc79e26bb +dist/2024-04-29/rust-std-beta-wasm32-unknown-emscripten.tar.gz=731603392b6e3d36b3a4956928d084e293ef18c8b8593efa756e753a2a309709 +dist/2024-04-29/rust-std-beta-wasm32-unknown-emscripten.tar.xz=8b681b3af47855eb63c4ffe06a2bc6bc4f365354ffbc171ce8cbd8c2a3588a07 +dist/2024-04-29/rust-std-beta-wasm32-unknown-unknown.tar.gz=7b87e59391493c3147c03794061111e25bdae669aea58190a951cdef111e75e0 +dist/2024-04-29/rust-std-beta-wasm32-unknown-unknown.tar.xz=d15eaadb101027906c2fce15b95a3f820bdbc4cf145b705bafc2ac5291289c3b +dist/2024-04-29/rust-std-beta-wasm32-wasi.tar.gz=07390ec742b79ec11b2c3ec65f60efe5d7c616f50c33058fce346f6e9ad21af3 +dist/2024-04-29/rust-std-beta-wasm32-wasi.tar.xz=79e34d46621c298cadb98c00ce3b25d97474aec300d85255153b47e21b7bb744 +dist/2024-04-29/rust-std-beta-wasm32-wasip1-threads.tar.gz=b916dc9051b0278f820ea0b093db3ecae2e27de641ef67a9b508df75dc92c938 +dist/2024-04-29/rust-std-beta-wasm32-wasip1-threads.tar.xz=2867922a39da3b02ebdb93fb78b010695daf468f87485ad8ab79c7f3eeb18b11 +dist/2024-04-29/rust-std-beta-wasm32-wasip1.tar.gz=792b718c0a72e97ba85a17ba67ee09e55b85de829fe4021f828ce54ff8cb31e0 +dist/2024-04-29/rust-std-beta-wasm32-wasip1.tar.xz=abff86499119bddfeda9059004549941dbcd3d911702d4a9c198b94f60e60f4e +dist/2024-04-29/rust-std-beta-x86_64-apple-darwin.tar.gz=0bcc7698efafb42a37f20815f5660e39829a42a2776304e7129d0a4ec0c7520b +dist/2024-04-29/rust-std-beta-x86_64-apple-darwin.tar.xz=c437626e250b0d06c05dc828ab81d0d2c543ffce4b100567910508974ea50045 +dist/2024-04-29/rust-std-beta-x86_64-apple-ios.tar.gz=7c98c9f491bfc837111769a45c10ce2f1ef73c22377158ef9ae80b38034892c0 +dist/2024-04-29/rust-std-beta-x86_64-apple-ios.tar.xz=f4bda724e6e382e02ddf4e4e7a479120420666a5a1ad3c87a85d4d3c763f2cb2 +dist/2024-04-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=01efbb2e48045318e18bfc7b6c190b461a219e81fc1cca6c855bf0c658aef556 +dist/2024-04-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=9bff316c6d2fbb3c0889f9ffe4eae496b293fb3afaf8d597155e6badbf0c6a8e +dist/2024-04-29/rust-std-beta-x86_64-linux-android.tar.gz=5da713547a8af2c86da7db5d8aa4c27188dea1089fded81ffbbeb0f78952a10f +dist/2024-04-29/rust-std-beta-x86_64-linux-android.tar.xz=9d6a45d6af395360c63ce97bcfc2f9a2967c708afcd979f17fa447239703a92b +dist/2024-04-29/rust-std-beta-x86_64-pc-solaris.tar.gz=d1a71110bee002c8edfbcc00e0f5eede5afa005b09944bb2cde469c658049e70 +dist/2024-04-29/rust-std-beta-x86_64-pc-solaris.tar.xz=6b8d18c83b9fffdddf9e55c807dc7d5784cc6d7ae90a57c29b87d707f0656964 +dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=28921ee14426f54aa09523547516437130654b2d9814120d286f209666c88533 +dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=7c3125cce30978ca2619e9aab150cb5b9b2535fbb6274d4ac1b1d4342c7b0220 +dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=ee5c237f092f8a4ba797c4c7769dfd4da81b5c86d2f4b88704d127642d222a22 +dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=30c84b04bd2d4d33abf1875cfee5f227ef6484edc67b3cc4c9c96d92c8406d6f +dist/2024-04-29/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=81274050e72c5a8ffdead83f7be62434f35a65517a1b3c6f7d9d14d0d59da710 +dist/2024-04-29/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=215e20c78a2a4edf9b8368a29a09af5f4cf8d0edd1995de3bbf2eff01127cab7 +dist/2024-04-29/rust-std-beta-x86_64-unknown-freebsd.tar.gz=340131cba121827a9753e19cb3a4b9ba2ebe30569fb20d7f9300b4dbe2a15cf4 +dist/2024-04-29/rust-std-beta-x86_64-unknown-freebsd.tar.xz=69626178bc5309afc8a02c941bd77e70e1aa6917ffb6bf0d67a57d921b5c664a +dist/2024-04-29/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=22c6c90533dad3a731ad8a6696e6cdc1b15579e25c658fa2b094185e1893934f +dist/2024-04-29/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=30d7ef6684fa98e28037b69d4220cba40489c23e80fe7793c98b388dc161757d +dist/2024-04-29/rust-std-beta-x86_64-unknown-illumos.tar.gz=9d7192d32eaa6b6ccb0f615da0f4cd80827ba6484eabeaf401d8217678f1e313 +dist/2024-04-29/rust-std-beta-x86_64-unknown-illumos.tar.xz=7a3fb35e0bb252d5f90773136d1417c26d5601beadb77d6da6f5ad3081977f07 +dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=e987635519c1edc8a1d147ca4a86283637e4dbd0a49736b01d605e45a3a14e8f +dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=c3ab6b97dccc0038c68494b03b6d444d534e447226a2b2e140af54c94fca0b2d +dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=72e8113687be8f947c50befb42b0957dd564f01693cf4d68d749a9e074032ada +dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=867b24f33b19f40727c71818c8a002718d44d4cd4ceca44314331e19c1adc1a4 +dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=f9b0fd9605bd4e264f5303bd740d9a0195bc147132969965b221f9da0d7875bf +dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=022dcf4887df41d776ba2666858b9aaab479758134a71f7c6b2172ed7c1a1752 +dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=b5ff4a0ecd7e0f71a9557b6096bb907e5cbc8982431f0d9b01d8e1a895d8b37e +dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=e40d5bfb46aadf6faf849df548154db3f35f356f8b98037a056802a235922b8a +dist/2024-04-29/rust-std-beta-x86_64-unknown-netbsd.tar.gz=57cfb1fa472dd9c01fc0caf605a55b7248375d616acf84ec12f6430d5e07e2ee +dist/2024-04-29/rust-std-beta-x86_64-unknown-netbsd.tar.xz=e4121f060b917c811d971e85ce02495e83150ddcceb2204615edff24bd55bfa6 +dist/2024-04-29/rust-std-beta-x86_64-unknown-none.tar.gz=d63559803c8eb47e0d10d9f3a2284477b570a2536bb541762774271451e1f0ce +dist/2024-04-29/rust-std-beta-x86_64-unknown-none.tar.xz=5388cf8ecaa234d507e505e8c6d433c5de8811b2717aa254e4caac9f4aa6cd97 +dist/2024-04-29/rust-std-beta-x86_64-unknown-redox.tar.gz=0f027163f37618df4330ecd82afece432b0a509ab20333d7b787c0d139ea89c2 +dist/2024-04-29/rust-std-beta-x86_64-unknown-redox.tar.xz=b1c722e894b145c2183183fa58762c64402fac077419dc7874f8b08eee665651 +dist/2024-04-29/rust-std-beta-x86_64-unknown-uefi.tar.gz=24e2ac0d44619ef9b76cb1af6178103d65ab12e2677b366e8aee0604798fe5f1 +dist/2024-04-29/rust-std-beta-x86_64-unknown-uefi.tar.xz=1d8a45f1bfe6650edc5ddfc8683190eff5a74384abcb2f73eb3d1e88d566ccfc +dist/2024-04-29/rustc-beta-aarch64-apple-darwin.tar.gz=ea113c567692d54983ab6c376761651b6dcf9bedad5b5d822d28c0d0d0733cf2 +dist/2024-04-29/rustc-beta-aarch64-apple-darwin.tar.xz=e36363f1ea531d2fd563f471758e387de37a34e7ef6f4c12175979657333c5b4 +dist/2024-04-29/rustc-beta-aarch64-pc-windows-msvc.tar.gz=52d77d540fc3f83d82f35f358ccd9055fb75453af3e3bee4b11636742559db13 +dist/2024-04-29/rustc-beta-aarch64-pc-windows-msvc.tar.xz=843c56f5431c1feda85ceaeef0daf988e8ae020b3556326fb1f75ea7968bf2df +dist/2024-04-29/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=ba2fe37dda1a487a2c75151895f4f6e886e9476a992272ce26e9b5fd7adb11f9 +dist/2024-04-29/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=ccb7be3935de1920509d2061d38f92f1fb8d2a5dd6cef392492242a929363fa9 +dist/2024-04-29/rustc-beta-aarch64-unknown-linux-musl.tar.gz=40636e0936bd311803317825c5fb6b446cdb5536ada1db097b567df04a86d7dd +dist/2024-04-29/rustc-beta-aarch64-unknown-linux-musl.tar.xz=804ef68f24bc0ba5150177d8b8515daa54aa82fcb61472385ef1a1d897c5c3e1 +dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=a320c2869d1d2c92b698397d4467c8498cad9481f38d28ac810bd165399ca46b +dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=7ce92211d87068d9c223806929adc34ca611a1321cd58b5bd81aabb0ec3ff085 +dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=79c16b902884301882d16be36fe75ecb32a8e49abde0038ce21cfbee883c2c3a +dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=9384eb9bdbb585b414b6c04c592a79e90a0c0ebfeeb970e5e1b920cb638807cc +dist/2024-04-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=ff99de5b819a4fb9adce9386a309b9841bd33632eb7d5079415a6ca6fc86b9dd +dist/2024-04-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=55635cde13af11dd8cc007d2e0499bfee493bdfba87b6efd7b1fa4115f5728dc +dist/2024-04-29/rustc-beta-i686-pc-windows-gnu.tar.gz=de82ac745275f069225b84574ed145afaf9f54abde5246592e49d5d1cf40cac1 +dist/2024-04-29/rustc-beta-i686-pc-windows-gnu.tar.xz=a8a7bf64d33c95a2f94265fba8dd9ac50bbb727f4bc3e79be5bf61212cb5d22b +dist/2024-04-29/rustc-beta-i686-pc-windows-msvc.tar.gz=88967a99c993d6e0c3c7948308510644286ac826266dbd3d89aaa083100711db +dist/2024-04-29/rustc-beta-i686-pc-windows-msvc.tar.xz=1804f75786482946258ff0e827274357c49e90a7f2f568add7353249f2ab78b9 +dist/2024-04-29/rustc-beta-i686-unknown-linux-gnu.tar.gz=3cb7e02c61d4a21d8289289b874b25e8b020c1d553e5af950160bffc14f51c18 +dist/2024-04-29/rustc-beta-i686-unknown-linux-gnu.tar.xz=2ad4b1311a0e39c359798375912faa91b4e13cd473bd59efd1e4f721777d254f +dist/2024-04-29/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=ab19efb741a127615b9022dedf1d895b53c69740cc3da745f9b9888bade9d98b +dist/2024-04-29/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=492cc11d54df410c2547890803930fc65950e6b81ced512e24bef56c3e70f3d2 +dist/2024-04-29/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=c5a631a41f417336f3f65c85adefd1fb0bacc02465485f37d29fc1223c9f6cec +dist/2024-04-29/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=0701183b615d9eec9daea724d4cd8fa98dede2260cfb6b137d6cbf8ad6b29a4f +dist/2024-04-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=cb70e92d5275862b500614d79eaea3d19319b96798f4850cb19dea9a8038a651 +dist/2024-04-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=908cbe562d82cca1bf176fdc99af867966ea423d244c4a50e14bad19f6878201 +dist/2024-04-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=8580a3eb6d6df1774f4b6ca06dc1195c42b1e2a463488a5d851e99b0ca6d0249 +dist/2024-04-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=2627948036e905f2e280663c56c86c172e2b0d057311ade7ca238953b7e0c36a +dist/2024-04-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=526e4f129fdb4b2c8f4317c57105a09ff03e71771d6d6bbbc9380917b5440d71 +dist/2024-04-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=fd9dcf60838376478d7cc505ec7fc39f86f9d042646a3b836e9c06825927c7eb +dist/2024-04-29/rustc-beta-s390x-unknown-linux-gnu.tar.gz=664c1255a9435d1ad086329a3c215974b9302d481762240cc9d0328d9f1b8c9a +dist/2024-04-29/rustc-beta-s390x-unknown-linux-gnu.tar.xz=a585ce7684e4174f03adb09df17221e1729e8179dbc91b9a0f8813c3ecc0822d +dist/2024-04-29/rustc-beta-x86_64-apple-darwin.tar.gz=59a1d91009b506a5bce3c276993cb8acfd71f73d01f9eaf4195b36114ac822c3 +dist/2024-04-29/rustc-beta-x86_64-apple-darwin.tar.xz=f86f3309cf2784b076f14e7da9e921c294a7701ea92d378c609061deccbc6bff +dist/2024-04-29/rustc-beta-x86_64-pc-windows-gnu.tar.gz=f5c074461409b33a9791325d4014e6861ad36f99b9e48e54ecceb73986450be1 +dist/2024-04-29/rustc-beta-x86_64-pc-windows-gnu.tar.xz=045431eec6f839b1c40b5a75c5000f80bd6351274a59b29d962833495324ecb6 +dist/2024-04-29/rustc-beta-x86_64-pc-windows-msvc.tar.gz=a3abfb68e60544170f47209bbf048f1374e5bb75901a529e2ac2f315758155f8 +dist/2024-04-29/rustc-beta-x86_64-pc-windows-msvc.tar.xz=398c41a3219781c7cf1a907406506526b672abca6d3ab59c30556390a5f992c9 +dist/2024-04-29/rustc-beta-x86_64-unknown-freebsd.tar.gz=38895e615efd0bf75ca14b0ab0a085527cca64fae17631d1780a8f51acd26d17 +dist/2024-04-29/rustc-beta-x86_64-unknown-freebsd.tar.xz=786f40030dbe5e6897aafe4bda44770920b2010b93fc5ce86574774e531e2eff +dist/2024-04-29/rustc-beta-x86_64-unknown-illumos.tar.gz=7003cab7650dae7e3d29032422a57782a2c146024c437a6466ae1dd2b61a6618 +dist/2024-04-29/rustc-beta-x86_64-unknown-illumos.tar.xz=bed3cc10203e8bd4d43b6245928c8a607acc5b6e633635caea45eb4eef4bda56 +dist/2024-04-29/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=84cdea91c9f1e848ea17f554229ca80d18d093fc609641d8f003c4f2d4871866 +dist/2024-04-29/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=a20fce7512f7c8cc6230a0f63f12855b04370d25e621183f71aa444c90c36b4b +dist/2024-04-29/rustc-beta-x86_64-unknown-linux-musl.tar.gz=87e0c484ade99efab57c655ef96dbabf7a02314540575b65a14372ab5496c36c +dist/2024-04-29/rustc-beta-x86_64-unknown-linux-musl.tar.xz=469757d8f35c9f4210aefd2ba660ee249e4409d47b908a6c68c1e650ee81ae67 +dist/2024-04-29/rustc-beta-x86_64-unknown-netbsd.tar.gz=4a38000480fe78fd5da7f9b71d36f296a6ae103254d932c4de6b902354e86bbf +dist/2024-04-29/rustc-beta-x86_64-unknown-netbsd.tar.xz=45945d6af237fe4c91fde7db02ca19e99bac56a911b8db79be9b6ab8bb3934e1 +dist/2024-04-29/rustc-nightly-aarch64-apple-darwin.tar.gz=0b07375a9a6507fd4932a05b5aaf28ed349fe2040103f1cb69c8a2494437258f +dist/2024-04-29/rustc-nightly-aarch64-apple-darwin.tar.xz=143bd7ed3ca7b913ddd0cea7cda8d1a0e4c29cc2ccbb7d29f0e45c2a87c3ec46 +dist/2024-04-29/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=9404c111b91fd092367b88adbc37dce10a98c443bd8d9e13a860e1fb4e3af96e +dist/2024-04-29/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=f9f432907c276edcae5ad8ade0264f3c03109be02e791a814edc8ad3d229637a +dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=33425c90427424f0b30fa2a6331a3b59c680f1c1bd0d8845d7e6bc1e2f80292d +dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=03792890c64c72f30143849894b15f0eb3d6ad735fceede9092abd900ee733e4 +dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=cf6f2bffa0db1b4b9b8e95801bf415dcce413f902e26f4c1831dff1a00752b99 +dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=9192fdb668df8d4cab776623db7d01e35af42fea94098c1d4ba53190825d81a8 +dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=a174e7e08da2abc6b84499360670188f5cc61b6d055967e04bf602ff3d831f45 +dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=5a59811027586863852b15fc2b603e7e69b19841f4c10d2527ef1fc5b77d8af2 +dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=645bb5dd7a96bb9292b9956cb9705e9aed2408e47728f245564f1f7404ede783 +dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=1fe34911b082c3a5ca4f24656675c095d2cf56f8005be9ca2517d0ef7d0a2b37 +dist/2024-04-29/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=f2d6403d81bb0afe2e14956828987a0bb044c95f2d9566e1d792dd922dad7914 +dist/2024-04-29/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=d93fdafcbbfd50c88c3f4feb4c68b053882ccae02c45e1615aeeae5a86f4aa98 +dist/2024-04-29/rustc-nightly-i686-pc-windows-gnu.tar.gz=a9e997b03559b3dfa2a0eba6ed7a142d7651ea7f4ba4e788d9de807b50558e58 +dist/2024-04-29/rustc-nightly-i686-pc-windows-gnu.tar.xz=4412b5fbfab8c5b31e57cf8c4ce9a9d13cfc9c0a8174ea1fc8a7c05281e1cb54 +dist/2024-04-29/rustc-nightly-i686-pc-windows-msvc.tar.gz=1725c41500dbf6bea554f3d4acaba70167f0e89087aaa3eb3c0f8a99047c55c4 +dist/2024-04-29/rustc-nightly-i686-pc-windows-msvc.tar.xz=27db022494afebbe05605f134191e8b2e78bfdeaa638d4215174038ca9dd2fd7 +dist/2024-04-29/rustc-nightly-i686-unknown-linux-gnu.tar.gz=dc1a05d49b773dba06808c1c50653ecac506b3433f0f6dfa307109a7c621cc1a +dist/2024-04-29/rustc-nightly-i686-unknown-linux-gnu.tar.xz=cc58ce3af8f5481ada4dc129079cd558664717526b2f7f9a02bde6bafb6f45ad +dist/2024-04-29/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=34cfe803126ae9218b17adfe833a55c697dfa50729ac83b642529f3682d12d15 +dist/2024-04-29/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=c752dc8962656c09047151fd24166f3134fbeed85006b5d22496691079c7fb9c +dist/2024-04-29/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=386b086b8aad922050c813dd58bb79a52ef806b2d1413e2e9cc46d6e43b81d7c +dist/2024-04-29/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=d9eec9ab7c265444ac5f04d4ec9e77d4c0c3c2e34c5804db8abf5f94c8fd2272 +dist/2024-04-29/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=91df129046443554bfb836d25886aa9807b917acbc9dcf30f6531cde7bf912fa +dist/2024-04-29/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=ca9b574b9f2e914b5a6d9e011aba805d1e6f9b687dc1a1868e88f0e4d9e4401c +dist/2024-04-29/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=8b44f96a1ccd6d501b0af3960edb2c1a6c93957676a1c2cdb831e614de398f8b +dist/2024-04-29/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=f8a10a6767b80bf24f73223b9e46e1b18b6bf6746ad2115eb8968a0e482f0e4e +dist/2024-04-29/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=a197208807503a9cfbc6df938d614a192da48884b2e4892f7b1d234579091be1 +dist/2024-04-29/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=af3a1a33942bd8a3417593dc118abb1db0373f5410f54771713c05bb86724fed +dist/2024-04-29/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=5a3a3aa73b6a0f21c63b9a40bdbd0bb4dc59bd75add0a06e292ced791fad31be +dist/2024-04-29/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=6d7903f1c9fc95a23448717326d667dce59e54aaff821443d3cd9137cf3537fb +dist/2024-04-29/rustc-nightly-x86_64-apple-darwin.tar.gz=64eede54da4bf88b0a42ecf7f7a4bf8002b5550e60a64e1e48244c7f5b04768c +dist/2024-04-29/rustc-nightly-x86_64-apple-darwin.tar.xz=0a8f95e3bb0bebf9bcc8116b91bab3ba97cb6ff4021713586280aaceed9da030 +dist/2024-04-29/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=58f9e0dd9c1aadde2dfd869528adadd4acc29ab0850236f3cee5f023d4211939 +dist/2024-04-29/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=a211a962093e0d09358d51a6eb48da0966a02383c6b00c8acc077b5663d7d707 +dist/2024-04-29/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=5631926874dc54204c319137a77a89de5e6f408de2a832109e2be71ea79f27d1 +dist/2024-04-29/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=a8cf87bc663b5e3dbcc97b0eb58bb1b9b5b0100aacb47dc0c372fe1612517244 +dist/2024-04-29/rustc-nightly-x86_64-unknown-freebsd.tar.gz=1011f98197a9fe82d6095f4521934a06eea5f7e9719a6e4c9e3bf13d68f799ca +dist/2024-04-29/rustc-nightly-x86_64-unknown-freebsd.tar.xz=79599b3f91f9372262e97a417f4e104ef5192c0f6f8df204aea9c8b3ee39430e +dist/2024-04-29/rustc-nightly-x86_64-unknown-illumos.tar.gz=7179a453bdcb17e401c0af8f4ab86cb5a4752a8ec80b0cbdd4cf1854c7f36a35 +dist/2024-04-29/rustc-nightly-x86_64-unknown-illumos.tar.xz=d565fc366fdbc305fbfe59e72b971c58f201d69e03a9ffa667d2ca0735cdb7f3 +dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=ae6bd8e20560d48519290d78e3d21f84b983403ca1f8f466a85496276d7866da +dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=c7c0f8f44b0275456a27952178caa04c32eb9a1507056ddc05926a0730e17359 +dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=3246797ddbc9118de819b13b005b83748338f3c825a7436ebd5aa79ca55539c0 +dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=c7e784e77dbabedad88d24d2ae6dc4abb68bc04b1cd6c9d45f6dc28b6d0e2edc +dist/2024-04-29/rustc-nightly-x86_64-unknown-netbsd.tar.gz=c9452de4b3f15f0cf0b7d737b217b2cc7b88a96543bd8ce587ee14be1e21a90a +dist/2024-04-29/rustc-nightly-x86_64-unknown-netbsd.tar.xz=de9b05278a5c69d53ccbb31223526ea2aa2275c0fb3f046d1c1b4d67c0b0c275 +dist/2024-04-29/rustfmt-nightly-aarch64-apple-darwin.tar.gz=3734353a58dbf6c3831cc6b4ea606357140c191c89e8dfca1d7aa2f3fb8ac53d +dist/2024-04-29/rustfmt-nightly-aarch64-apple-darwin.tar.xz=e5e3a6e609fbfd537aa4acfefd3681d4b6c8029e2801a1ef23e8b09cf5a47bfe +dist/2024-04-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=22f54857e01d759301d099b67547cdc485596499088d0d749d38058c28e0f752 +dist/2024-04-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=db48a9d45dc7c7aad4c9bb0d20789dd35fb6ef7a966948c44fbbae132de4c16b +dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=fa5d1fb9f3627e7d59269a1f8008d780c685ea04975473f1808287134e7bc5a7 +dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=61ab625b47fa9097af90a79a1e75a2f2492a415f4009c9043cf453bd4128f031 +dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=cc79969341fc60991059d0e3f13a69489c1e0915ea5787a88b8605ed5b7f3cd0 +dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=bbdb75f922b4b1716b033d91c76c4c0aa53061d6e7fa53a9bf16fe076814bbb2 +dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=13ca68afc3f3970a37951504664b58035102e1ae06d10a744389603b2f7499f5 +dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=04b174aa724945b6359a555892506c6a742a7c427464e8206433bb3f9a65fc02 +dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=430333380a590a9de211c8d735989fedb89321cf9f5f9a0b1ef651ec8b598691 +dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=924713e648806945cd56e54d4c11dc74b65241c8dbf6cc7b401c5c93d0f7ffdb +dist/2024-04-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=bb6e5a8b5cc88099e613aa5f4d926165976d8e4a7fccbecf4ac3b0eb966d7a0f +dist/2024-04-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=34d5e970304e1734aacb26c095e926c27a07e1a41fe70db9fa2997bef97ad3ec +dist/2024-04-29/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=835447a1d9d60659e99903275f327641809fc0148f35149f980d1a17ff87cc9a +dist/2024-04-29/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=ddd84a7f900aa239f93711f7da71e57aaedeeba2c9c8a8f23608acc7e48613c0 +dist/2024-04-29/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=02f0af2bdae167c6091099a9b54ceb150c22b0f20dc861587a02cac78deb0b39 +dist/2024-04-29/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=822f78f39dcbe3282bf7888a8cdae04efe7b023ded026a7e7f430e4ff15e7942 +dist/2024-04-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=68a6189652c11a2c142c5339e2f5fb09d5f3e85d860bff063f62d5d3a3d111bf +dist/2024-04-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=6740ea882effa2fb87dd72744c08888ce5ec59c9797c00369156b24847bb180e +dist/2024-04-29/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=0bb365e2d895ef3c39c4899a01187a23f9b7c5195c30bf845da3917f62f5eafd +dist/2024-04-29/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=2e54c9887bc6ed1eb09b9f69c8425da843ea12bf33248fa0ccdc0d14387c1c57 +dist/2024-04-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=b0c0fe437921d17e2f50cbff87beeac067efa3d5211a241fb6f4c10b8ab500ac +dist/2024-04-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=64e7282c0cf4a714b11eed1d28be3a64ba0ccc6d899211a872a5a7809d514c08 +dist/2024-04-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=100cfde057c81460b8cfde2047fe83ddde360a6df1ff178da5a968b17ecc9df8 +dist/2024-04-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=38e8712e98fa0bc6962ab2fd2e3b96a2a5dcaa6c16161d8caf71131a1ca5031e +dist/2024-04-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=4dab52b50e19348fb39fdad39ab44189c27c10f80b5fbe2cc4723b644611fa87 +dist/2024-04-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=36d1b2c9150fafc5976c296200ba3fac3e923df3e6f18032068200e2a887146c +dist/2024-04-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=7cb4a536320c23d305ce3bd3b7a954d951bf4d358ef3732be75b9b290c4818a5 +dist/2024-04-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=ede1afc7dc5892ef6f780e987737e145c4b4d00495da8c2e9902182a3a174e20 +dist/2024-04-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=e2d2d561cbfa0add0e5349682976216d3a7cff4094372c1ed26854bb4e4d93fd +dist/2024-04-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=e0380e65e83e4131f6aa7ee4e185689add4372b0c1653312e2ffd56072fdd0fe +dist/2024-04-29/rustfmt-nightly-x86_64-apple-darwin.tar.gz=73a140c7ed9c80f209ff976c63b0a34d625d651553c38692c91f048f4e0ae470 +dist/2024-04-29/rustfmt-nightly-x86_64-apple-darwin.tar.xz=9946b7120465181e05916b8023bc075b32bd85cf45a3b1d8bfba2f94ac78d927 +dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=eda273f27714b1e45adcc2388149f48de0e32a9104db0b9d1a02f6d37de43fef +dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=f2955a4b696d050c219a96c093162b42a2fab921f9f3cb7570f8462928306c6d +dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=ec900cc2d3c6d45ef039653f4418f9b9a4a5fddd5d7e8077c3fb08b36c539a28 +dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=04e6999a3405acc79f5fdcafeeab52880e5eeeedd3909b5f3c57e7647c86ef99 +dist/2024-04-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=0730c5ebd576fec5371085f9fac0adde9424e1d7626456ed33bc66351b0ad307 +dist/2024-04-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=90cbd84b8d48f0235a1954166f5edd53dc3031532ec6dfcb364f9a9624c9ce11 +dist/2024-04-29/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=5f5c62d321db27eb495f6ea312ef8bea0bf17a7a501a44e062986c416951700f +dist/2024-04-29/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=a3bf64e2f22436e4484fc818f69d2f750fddd05a96463fd4abfcf655edce36b9 +dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=a847a6f9c7a3ce71c7cd8d81bdfcfcd8e4d128aa28ba0dafea89b0cc37c6c36c +dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=21fa794456566c64d08f629a385f89b3cfe9d9b69f317ae85fbe7425419108ff +dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=b3f792f10a98993b4b55d1df951727a4422102d51b1145e51824268d48587ad0 +dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=d791f0ec3c004e7baa0381962bf8ca2f18a3c861152702de5301d0149260e7fa +dist/2024-04-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=9807b2887e976d29f0c04484f8459175b4f6b70ef000037cdc4dada48e3cbd74 +dist/2024-04-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=019920d64778af62879e2146c2c13d9f6e2165a38bbfa1982694bfb48864d308 \ No newline at end of file diff --git a/src/stage0.json b/src/stage0.json deleted file mode 100644 index a9a53a7528fee..0000000000000 --- a/src/stage0.json +++ /dev/null @@ -1,456 +0,0 @@ -{ - "config": { - "dist_server": "https://static.rust-lang.org", - "artifacts_server": "https://ci-artifacts.rust-lang.org/rustc-builds", - "artifacts_with_llvm_assertions_server": "https://ci-artifacts.rust-lang.org/rustc-builds-alt", - "git_merge_commit_email": "bors@rust-lang.org", - "git_repository": "rust-lang/rust", - "nightly_branch": "master" - }, - "__comments": [ - "The configuration above this comment is editable, and can be changed", - "by forks of the repository if they have alternate values.", - "", - "The section below is generated by `./x.py run src/tools/bump-stage0`,", - "run that command again to update the bootstrap compiler.", - "", - "All changes below this comment will be overridden the next time the", - "tool is executed." - ], - "compiler": { - "date": "2024-04-29", - "version": "beta" - }, - "rustfmt": { - "date": "2024-04-29", - "version": "nightly" - }, - "checksums_sha256": { - "dist/2024-04-29/cargo-beta-aarch64-apple-darwin.tar.gz": "5a8c5e48a88e7c7b41eb720d60fbd2e879b97639c7ff83710526e8e6caaf8afb", - "dist/2024-04-29/cargo-beta-aarch64-apple-darwin.tar.xz": "0d237535ae8d435d99104fa5b9dbf41878e2304bb0f2eb574bf17dd685caadc2", - "dist/2024-04-29/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "c56733bb6198af0a9b0df9a44ef979150e00de33b70853c239cccfcce23c328f", - "dist/2024-04-29/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "7da5f887151215ddec640684077d98551fe2aed75a3ece2c73b20698754a70bb", - "dist/2024-04-29/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "73851e304a539d41bedc0d8a5d98800c8279ae623d3e58e863f8c1f8b458b01c", - "dist/2024-04-29/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "db9c28841344b0154756e19a21795ef6e0c4e27c7844be9996824f1039edaa81", - "dist/2024-04-29/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "a706c8c7e37b9e80d7faa000c5d179a772746eef071387fb2879fdeab1f1f891", - "dist/2024-04-29/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "2060634afe1b4a19bae874c6ce3cf4256e613af26e06104b45da5bd71cfb133c", - "dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "7af61e74faea669fdd41793e4b88eb6a37bfacf845af364ee02bb7cf08c612c7", - "dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "4759fb3e3d89ead605c4eeba23be5cb9b3ac98086a9de20f8dbfdfa9282ee486", - "dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "4cab18df2d94702e8b551357373bcae60d1023e644148f0f82e8971023362121", - "dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "7de4f0d72b4e5770376ede82b02d6bcfd450788a40375fad34d75524c941d72c", - "dist/2024-04-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "6401391a426cf33d6c58f07e7b2828b178720cb4f2b8577ae932b5f5b7d6744e", - "dist/2024-04-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c3f6729bc769325046f0f62c51b5bed30068c37dc2a36a6283e50565d8cb7d5c", - "dist/2024-04-29/cargo-beta-i686-pc-windows-gnu.tar.gz": "d116c97c1242220c7972b63010aee1ed36bf5353e84a06d3561cd5fe9d7dae84", - "dist/2024-04-29/cargo-beta-i686-pc-windows-gnu.tar.xz": "65eba577f7775b3eef36e7f000b5007264392b20a7759f8ed567f3a45b2877db", - "dist/2024-04-29/cargo-beta-i686-pc-windows-msvc.tar.gz": "d418a3371b3631328bde2b1e0c3159700f12424e83b1d8ece1349fea90f9e403", - "dist/2024-04-29/cargo-beta-i686-pc-windows-msvc.tar.xz": "23ae73c776fdb0795944656d743444e3b4c440f45084028206c1aec52333b1ba", - "dist/2024-04-29/cargo-beta-i686-unknown-linux-gnu.tar.gz": "b6bbdeb7c8bfac2e8a083adb4782caf5321799f47acb4eaf81da32bd11730e9c", - "dist/2024-04-29/cargo-beta-i686-unknown-linux-gnu.tar.xz": "6b409691da6ddb8c04409667b2c3d9d6429c6b5bf53ad18177248406a5f06cb9", - "dist/2024-04-29/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz": "24cd888d14a788e8fb5b886735f3c07a028a8681df48a777b2bb971c62a175ae", - "dist/2024-04-29/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz": "e8eece6412936fe4dc863a5e19e6766fbb20e81da0069ad7831465e638db23da", - "dist/2024-04-29/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "8f007a2aa02e35c5ddb2152cc7589092a0e3083211c6aa23e676e3a3ad5a4b8d", - "dist/2024-04-29/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "3e423e693dd0813f5d87d9eded94894076258ece56684f3598321cd013aeef3c", - "dist/2024-04-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "2eec5e45e389a52b526a5cf683d56a9df92004f6095936b16cd8d7d63722cc6c", - "dist/2024-04-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "64c5135cbff9d4fa9575074c55e79d85f72cb1783498a72e1f77865b9b2d1ba3", - "dist/2024-04-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "d64552a80ca386728e42f00d7f1c700b5e30e5a6939f32ffa15a7ce715d4c8e9", - "dist/2024-04-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "fe91adce8ba35bf06251448b5214ed112556dc8814de92e66bc5dc51193c442f", - "dist/2024-04-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "77aafa8b63a4bf4475e82cd777646be5254e1f62d44b2a8fbd40066fdd7020d3", - "dist/2024-04-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "c38f0b4adcc8e48f70b475636bbd5851406bba296d66df12e1ba54888a4bf21a", - "dist/2024-04-29/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "c05df24d7e8dff26c01055ad40f9e81e6fcb3ae634ecc1f7cc43c3108677fa0e", - "dist/2024-04-29/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "47e8f4ec4d996600e60ddc49daeeb43d4c21e0583a86c12395c16eddc7db76ee", - "dist/2024-04-29/cargo-beta-x86_64-apple-darwin.tar.gz": "f024bd225b77160dc2fabde78002c8deac5cbb9a35345340964c3b988b0d1791", - "dist/2024-04-29/cargo-beta-x86_64-apple-darwin.tar.xz": "96c9e44bd9f0c85c793e3dd6043cc4f89fbeeab5ddf0fdb5daefca8f690bce05", - "dist/2024-04-29/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "517889f222b62150fe16bcfd3a0eb5f353956b0084d85713480197bff4558145", - "dist/2024-04-29/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "a6653ea4aec51569c1300c044d8bf2517a1f5111f710d12cd352190425b8f317", - "dist/2024-04-29/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "4cb5b5054dffe6721efbbf29192a67e59cda69ea4ab4791aaec6f314eefa5a5e", - "dist/2024-04-29/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "08bc45be22e9e4f615d1c9e70500046c8db89045f5d40dcde853c610591712a7", - "dist/2024-04-29/cargo-beta-x86_64-unknown-freebsd.tar.gz": "9661357ee8ea8973016fdbaa2de3cb98713136dcd25f07aa9f9d101180276815", - "dist/2024-04-29/cargo-beta-x86_64-unknown-freebsd.tar.xz": "7fab806227d1a3be817602abb121ac7e039ba0bbf81e0a1d47bdcccca74203c6", - "dist/2024-04-29/cargo-beta-x86_64-unknown-illumos.tar.gz": "4c79bb48cfe64bd38af7fe3660cd8bdc99ec90738a0d8fdf80843ecda910dab0", - "dist/2024-04-29/cargo-beta-x86_64-unknown-illumos.tar.xz": "0fb9edfdafde1820ccb25c22369cafb0e75e68795effeb615cb284a5837c75ba", - "dist/2024-04-29/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "c1902a072e61ab5ae9737a1092732e3972deee426424bc85fcf8702adffdd41d", - "dist/2024-04-29/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "d39ea1195dcc95e428bd540abd2db5b5d4c997a7661a41a4c0ca41cbdd18d27e", - "dist/2024-04-29/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "0edfdb6f6bb2a4a1a96a5e95cec897c444c936e6624bb4a530ffed4847b97445", - "dist/2024-04-29/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "70c264b7845febdee45d0c6e44b65d47ba7f367ef33ec906a9fd7f992ba7cc13", - "dist/2024-04-29/cargo-beta-x86_64-unknown-netbsd.tar.gz": "f1bd6417a54f3b53d572ce4af799242db7c11265c71201cc09c78d71be38c13a", - "dist/2024-04-29/cargo-beta-x86_64-unknown-netbsd.tar.xz": "53569810469c483785333759f86434706ee5368d5e18270ee13a17817ad57d40", - "dist/2024-04-29/clippy-beta-aarch64-apple-darwin.tar.gz": "7b693bde61a090854527a145455ff774314c65ec0cd47d25a19c76c6a166d96c", - "dist/2024-04-29/clippy-beta-aarch64-apple-darwin.tar.xz": "2494e9fdd8d342b6bc3e55eecfd555c43e3cca8421f3236df2d5a366288fec62", - "dist/2024-04-29/clippy-beta-aarch64-pc-windows-msvc.tar.gz": "90307f09c6fcb0c1fbe3ad1522a5381a17e2f69637c6d00f4a2cb5f3149bf736", - "dist/2024-04-29/clippy-beta-aarch64-pc-windows-msvc.tar.xz": "f7e0dec4a4862bd85d894252366152b3b6a7627e7e5a25ce323fa2db3bd87c2b", - "dist/2024-04-29/clippy-beta-aarch64-unknown-linux-gnu.tar.gz": "7c719e38f2a1030ae61985205df52f9a0c37b659463a5e2dea8e60e632de2d73", - "dist/2024-04-29/clippy-beta-aarch64-unknown-linux-gnu.tar.xz": "181ff4ae6adced6522a4c29869be3cc5dac8b961c7c88f2957cd31f831490807", - "dist/2024-04-29/clippy-beta-aarch64-unknown-linux-musl.tar.gz": "4e0e63e6f200386995e369a2673867d1bc3005d51d6a57c00ca80056dd85316b", - "dist/2024-04-29/clippy-beta-aarch64-unknown-linux-musl.tar.xz": "3d5b22a13aed6821482e60d9cc8571e2da9d95d82104284b77c56985a35a9c4e", - "dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabi.tar.gz": "9f788db76a5d55b3ecdd04a70b0e2be466959f76ae9fd3497ca2c503504e0c03", - "dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabi.tar.xz": "f4d8fc103807fba61d71d88b8e25a7016bfbd1a2905330f9a9fb3d7ba082713a", - "dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz": "d61bec3d017dd0be43e48350190ad18c0a0269e43d964600b62e1f7fd4f84399", - "dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz": "c00cbdc41a4da0c313a1a282b0158b059dd34f640b582cb7ca18e3d290ca8fa5", - "dist/2024-04-29/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz": "52143a530ca5274fbb760beecddff16f860ea787443d3dc708dda7c8f32ca9bd", - "dist/2024-04-29/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c6d2dfeac6f40811bc9b4cec3c23f9c3bb46f761e006257b9313aa7c1a647b5a", - "dist/2024-04-29/clippy-beta-i686-pc-windows-gnu.tar.gz": "325d39e426b1907fa17d93c0752d3d73bd95750f4f967c2a84aab2c5dac8a588", - "dist/2024-04-29/clippy-beta-i686-pc-windows-gnu.tar.xz": "536f591d4da455302029384ed196932d71119ef0160ac5415617d6b777c51123", - "dist/2024-04-29/clippy-beta-i686-pc-windows-msvc.tar.gz": "c3684c9bf471669d444853bf484880d17e150ecb0e7505de90883382023e343b", - "dist/2024-04-29/clippy-beta-i686-pc-windows-msvc.tar.xz": "0b00e6132f73d5dc762e359b0005fceab0cf7b01337d8f4aa9eacfb4552f9245", - "dist/2024-04-29/clippy-beta-i686-unknown-linux-gnu.tar.gz": "c91c1eadfc4cbae360a0eecf11c32d2509b68aca86c7b1de3b102944f43e1511", - "dist/2024-04-29/clippy-beta-i686-unknown-linux-gnu.tar.xz": "6f7a5a287dd6226c203bb674ff02ec773e5d0813091b2af744b88ecd6997a304", - "dist/2024-04-29/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz": "58383f094995823ea6db6a87b9ad4b33bdae2264d29bab88ab71ec60ccab3b93", - "dist/2024-04-29/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz": "dbf4680a6fd4dca54acca5503a7fd94502b8e85819bc02346ae9cecd275e4514", - "dist/2024-04-29/clippy-beta-powerpc-unknown-linux-gnu.tar.gz": "e28eb32cda42654c0f0247aa8e15f01f73770b36f7626c8d6f1b7659accc56e6", - "dist/2024-04-29/clippy-beta-powerpc-unknown-linux-gnu.tar.xz": "fcc48a83b748e1e46f9daef40563f8e5abbb0e3f014a168b04f3c700c2ace2b8", - "dist/2024-04-29/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz": "b626faf3275fcd196cd627e8a36c67721bae16a56f61cd080c79d137b3ec7737", - "dist/2024-04-29/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz": "2c599d2dc719d69f67625f3c6573fcc4f1ea3266801557dd3892bdb7c761b4cf", - "dist/2024-04-29/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0bc1f546fe0cef2b9516231ab608de68d55f72022fbc9ced5101b600e005f8c4", - "dist/2024-04-29/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz": "993294f2ae5202785ab242c1c6567df9c8ab1ef44ad35748c526b7fe854fb94e", - "dist/2024-04-29/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz": "210a4f0d208e0c8e13a57fb3b3e6c98ab5f620e4988d10a127ff1424ac1d5ca9", - "dist/2024-04-29/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz": "f10f7df41a13ee2ecdc25d60e697cba2342129a912ef20d8bfca5f611a9ec97f", - "dist/2024-04-29/clippy-beta-s390x-unknown-linux-gnu.tar.gz": "3e24d2af65f0c9667c9997ce091711b2be48e673de3707cddfd8cda455dfecc7", - "dist/2024-04-29/clippy-beta-s390x-unknown-linux-gnu.tar.xz": "0e7b8fbd0207489e38c78c2ae1aa0df4fcbdd84741aa50a86379e4d7ede286b1", - "dist/2024-04-29/clippy-beta-x86_64-apple-darwin.tar.gz": "9c0c47fd97ce72abcd6126315834c62aa7297fe09d447ee4cefa1eb46a116326", - "dist/2024-04-29/clippy-beta-x86_64-apple-darwin.tar.xz": "49dd65c5340fd804399edfa2402cf255fd9bfce1f4aa7fbb3c193c11bc03f8af", - "dist/2024-04-29/clippy-beta-x86_64-pc-windows-gnu.tar.gz": "6c1c3bdf097a1846ae08b098c555c0c5e9e9b646c744d6bb5a855789196b8bf6", - "dist/2024-04-29/clippy-beta-x86_64-pc-windows-gnu.tar.xz": "0a7319d1062f73af1c8f0efe6ad970d10d02259162c5bc84bb1f3a10f3911bcb", - "dist/2024-04-29/clippy-beta-x86_64-pc-windows-msvc.tar.gz": "52fef3f8a64fa58934a633bd4944e8ba9e15f2c2766d0f302dea1a6523864dab", - "dist/2024-04-29/clippy-beta-x86_64-pc-windows-msvc.tar.xz": "8fdbe7590e62ab68a2e463b14da2595e8c4592744f578a813f64d430ed7db4b6", - "dist/2024-04-29/clippy-beta-x86_64-unknown-freebsd.tar.gz": "509bf535622bd26385184ee0c17e4e27a5061a8aeebf5759f24bd578692b2f5d", - "dist/2024-04-29/clippy-beta-x86_64-unknown-freebsd.tar.xz": "2fcd10ada329ba7633616bebc584dca13f11c465e7cf513e76efeb0c3174486f", - "dist/2024-04-29/clippy-beta-x86_64-unknown-illumos.tar.gz": "ea8cea0d4a2379bcd0693f6174b25bc1f90a016dbe8280159cbb61d859806fb0", - "dist/2024-04-29/clippy-beta-x86_64-unknown-illumos.tar.xz": "5a243df8d1345db6bd18e4386ba628e6d302bce1cc572fb447cca4264fda3ee9", - "dist/2024-04-29/clippy-beta-x86_64-unknown-linux-gnu.tar.gz": "2ee560d3c1e306e103eb06d8e8033cd1489b3f6ff9df3bd8a95e25e977befa27", - "dist/2024-04-29/clippy-beta-x86_64-unknown-linux-gnu.tar.xz": "aaf6e54184a65ad6592bf03955a84ad12b561afd86064b1ac5fa03cf637052f8", - "dist/2024-04-29/clippy-beta-x86_64-unknown-linux-musl.tar.gz": "1b3877424a0a0eb507675a50e9d2c793f00ab85f6f12b1e27f871331070325b8", - "dist/2024-04-29/clippy-beta-x86_64-unknown-linux-musl.tar.xz": "6df5eaae5afb64557ba5c3a53ee3e56dab85455838a6044c7671c1180acfeaf9", - "dist/2024-04-29/clippy-beta-x86_64-unknown-netbsd.tar.gz": "1ac05ed7b607fff8b77ff203a663e9f4f2487779bc25e2dcd454cdf5b7583328", - "dist/2024-04-29/clippy-beta-x86_64-unknown-netbsd.tar.xz": "da502375b3cee8b254ab5999809f522692c2d1d90ea0544ad03c0ca514c65ef4", - "dist/2024-04-29/rust-std-beta-aarch64-apple-darwin.tar.gz": "2fdd35ca3b3e3d6f548f11c93337f5bf2e3c088bc78a79881e6f8e230b38b9a5", - "dist/2024-04-29/rust-std-beta-aarch64-apple-darwin.tar.xz": "bc16b3a1ab6ed69f0121a117c50cbcd201500dae4d72ad0dab148913d04cc529", - "dist/2024-04-29/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "9375c786703c17baae1c2066f8d972ac316bc840e478ecd1b94288a1d428324e", - "dist/2024-04-29/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "50d6818a8dd3ab7a3ddbbd7a062b538d9ff3ceb6eada031d1c22ab1dc7ba512c", - "dist/2024-04-29/rust-std-beta-aarch64-apple-ios.tar.gz": "56c3a01e8fd5c2ed75df811993b0b724709fb5473cc308ac09e7f5644468f751", - "dist/2024-04-29/rust-std-beta-aarch64-apple-ios.tar.xz": "3527d1f2c99c806479fb4b3801335dc921b514f171b82cd252cbbfc9ed30b163", - "dist/2024-04-29/rust-std-beta-aarch64-linux-android.tar.gz": "bf8cae7c66489f1aa27f1dea1b37f0d0ae514a6e21b93ff2dc6400dc88feca03", - "dist/2024-04-29/rust-std-beta-aarch64-linux-android.tar.xz": "46799f0bc1b3c13877f6cb732774cb3b33e0d8a081bfb56d0f877e79482aa1de", - "dist/2024-04-29/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz": "9f90fadab5104e1d415edf3b4edfaf7222f9f0d55f849851efdec74ffee16f8d", - "dist/2024-04-29/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz": "87ed6774202b18691bd6884df6944c7e9fe9c944b57a2837e7a7647518bf94e8", - "dist/2024-04-29/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "4a0692ad28f7f130b472ffa4aa766b745ba01fb75aa921f2da6622c9c68750df", - "dist/2024-04-29/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "a3d45962489a1e18a87e567cbbc8d3665f38809d0ad2ef15bcf0ff9fb9f470a4", - "dist/2024-04-29/rust-std-beta-aarch64-unknown-fuchsia.tar.gz": "c724f4eb135f73b9c79618f27a1ab35dc7b9d26ca62ed796accce68f9e747a66", - "dist/2024-04-29/rust-std-beta-aarch64-unknown-fuchsia.tar.xz": "8eab25782d16bcee75f86ecbb826346beb4a7525b220b45b3ba05a567c6d4391", - "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "33ab1f8410edf590570d7468dbe2ebb5a0907125bbc8d360a928dcb355f0d0e6", - "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "d3d870209a55ac96391affaa347c04f48cf98c089ac5056f340b8bb38bcc8e60", - "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "4d2bb72b898c30a2fc8d5d3333c2e99a8e30c15891fab641b6a519dc9f0cb611", - "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "fa343e6b6110fcd0c5dae4287ff1a799de5d7e4a805dbf4e9a034bbaed2bf269", - "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz": "f1ec4139783169fd83e1b0184518ed25d26cee7b21f196deecc74e83a1d78725", - "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz": "d100be2f6f0346c4b1f5b41aec0c13a47426bf4d49127f2341c8332903e4e782", - "dist/2024-04-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "bab6051e1071a58cd126580f6644decf16edb4473fe4be6a34791610d820a294", - "dist/2024-04-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "d9b68f06ff23629063e92dfc42aa3115a858238d368e4b52b35c1ea4491b1402", - "dist/2024-04-29/rust-std-beta-aarch64-unknown-none.tar.gz": "96804c2d9accd3242bdc22dad688b2ccee071952477b9c592f099377aee6c591", - "dist/2024-04-29/rust-std-beta-aarch64-unknown-none.tar.xz": "3fed6812d84bdaf787e85c37e23ba729b81a6d25a2b33fed75320e66e6641c89", - "dist/2024-04-29/rust-std-beta-aarch64-unknown-uefi.tar.gz": "8da5f301bff35fc067ec7cfb878ebfa5607af7dbc276a6b34a77404432c700d2", - "dist/2024-04-29/rust-std-beta-aarch64-unknown-uefi.tar.xz": "80d643189dc9af98b6410a01261ce6ad34b1325f3aebf3ff61fb43f1261b41ff", - "dist/2024-04-29/rust-std-beta-arm-linux-androideabi.tar.gz": "2e86b54b0d1f7fefead11d6383bdc80fe0a7b3ccf58381d2a731e6f1c62926de", - "dist/2024-04-29/rust-std-beta-arm-linux-androideabi.tar.xz": "9831a0270457cad2798b5ae4fe956c257c7e10ce5ad211793dc467577cdec29e", - "dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "f96bc303c0c2be9cf589f00aa63b2cf3fb8585ca9dd8860fe525821bfa1fe19a", - "dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "e57a053b1c2bb6fad93dfaffedce7f48fa292196fc8ba6fd2f0c74dc810a13a9", - "dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "49b2cb2ba5296871b5fac5ad9a74a2891e8b78321078a455ba4a65e003bebd40", - "dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "0f9c15d834a9d282a4018934759f7b48ef3d275e09679a68c5fd1b3f047d02e4", - "dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "e59f92827241e670c1aa92b35235ad12340869d59327fb83084b5f4149acbe06", - "dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "ad1cf96bb1fcceaa016e29e8ad34b4cfd711d2e0bd7cabb9cd7cc28abf64d894", - "dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "14a6d318af85bb9fa5c229e45a88a32a71f44ed02cd90a24bb67921eb64dee41", - "dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "ed6b48502ab9169818bceb300b4e6b4fd63366ad5808b047bf9988dae04c2729", - "dist/2024-04-29/rust-std-beta-armebv7r-none-eabi.tar.gz": "345e8a023be55e3b88a0c2677ea28c7bb4fcc5f3ab707638de76065c7592c2d5", - "dist/2024-04-29/rust-std-beta-armebv7r-none-eabi.tar.xz": "6d9b11d08f2d62611327a893b45ba07c36df11f077250496ab0881eb7ac84c65", - "dist/2024-04-29/rust-std-beta-armebv7r-none-eabihf.tar.gz": "a2ae1bf003a8a12b2ecb6bde9868a978820f184af523f0e4c3fc935edd509423", - "dist/2024-04-29/rust-std-beta-armebv7r-none-eabihf.tar.xz": "3d1dcf8308f9d4590b429f6abbf8f42f04496ab490ccf4ed8c9e381e6d886cae", - "dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "a54106d27e4ce97463e7867ceff9dd22ba456f840ec23229e6909b37d48ad554", - "dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "e6abfaa0905a00efeaee85b9f93793bab93e2cf4e172c9d829c5ba85006c688a", - "dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "cbed18e5dc61fcecb2920affc3890c3b8ae46b7fe5a80b3288689e18d490f3f4", - "dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "2b58bb0dd5cd2c5f7f93f4c6e9135090b931e0ffa27ff9efe2b8ff9fbbb7e48c", - "dist/2024-04-29/rust-std-beta-armv7-linux-androideabi.tar.gz": "6a371c2ececd349dfa76a02563069912fc91577ac4446d36c22f96723d7f5e9f", - "dist/2024-04-29/rust-std-beta-armv7-linux-androideabi.tar.xz": "9325daf41ddab02fa845971c10a5e0538a18c7bea14e66fa0f5f6fb16654c7ae", - "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "7f5ba76cfb7c85333c8dab76fb4ad3f12ddc254b95f9ee07fadb8e1270a4f767", - "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "f853b7f929b7a309ed6c08ff8c57d583ce0ccb19270674fb30e63a873834dc87", - "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "0680005d0a12498b687afc583d4f36bd67d0877cd9d3323bfd2df50d15c27afe", - "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "a494b78fcad01c83df9522d460ac2d35d2d00736a921381f2c611dc516edaa16", - "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "cfa555db31b5470e878b0f53d86617e7342e8bf018fe62cb0271dfe13db95f51", - "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "0a8ccd6d88cbe79a855111fbda45aa1a728de655b6927f3d429d901d2afc6503", - "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "eac53424001c884a540c42f0b68447349ec5d0601a030c060aaed76d54895728", - "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "42d78fca62361ff28db5bc43bb01cef7af5c6f4ab2110fe6170c3dce4707aab8", - "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-ohos.tar.gz": "c88de9f2e667da73177fb9c9309d7f1f467e31c18e3ae50d722c71ec8dd876a4", - "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-ohos.tar.xz": "24b3c04a42d511cdc8c6107b597be38981114f0574eced493d0e90fc748094bc", - "dist/2024-04-29/rust-std-beta-armv7a-none-eabi.tar.gz": "cd4ad182a098c61550265879ccc04733c39110827f7ef62eecfb8c120ae4ece8", - "dist/2024-04-29/rust-std-beta-armv7a-none-eabi.tar.xz": "8499a014dfdf448f474a58f148784c2eef245dc909587d876d2fb9ddc6a4ec3f", - "dist/2024-04-29/rust-std-beta-armv7r-none-eabi.tar.gz": "e8e1870e5b12b3d8643d712efb91eb86b2081284cada4a140c1526692ab183c4", - "dist/2024-04-29/rust-std-beta-armv7r-none-eabi.tar.xz": "d6029121eacc44bd4dcd9ef6dd3cd0d775cb6e9a3d99f3d62d746fcbf8981cab", - "dist/2024-04-29/rust-std-beta-armv7r-none-eabihf.tar.gz": "1e0fc42c3802e205130c01ca90f92d793c1c5427b34da66fe77b97cf67b4a5c1", - "dist/2024-04-29/rust-std-beta-armv7r-none-eabihf.tar.xz": "4c8cfdb11bb686111fa4842d13430c86d9d14ada30e9df334b3777fe899233e0", - "dist/2024-04-29/rust-std-beta-i586-pc-windows-msvc.tar.gz": "ff895c1b39b84587f10903f4be13d275b545e690da6761190d12c01acc25c6d8", - "dist/2024-04-29/rust-std-beta-i586-pc-windows-msvc.tar.xz": "fdcbcff7b740235bb16e44174fff9080a7c0a31be358c8abc41805c02c20c3b2", - "dist/2024-04-29/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "6b227f3b9001e148b66b7001f753a6f88fef9677e39d8fcf4d9c35fe8d345568", - "dist/2024-04-29/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "1e29297beb8de3778ba958731294823d9a93aac1e0d8833abc5aa99e2935965b", - "dist/2024-04-29/rust-std-beta-i586-unknown-linux-musl.tar.gz": "26481ad5f22a319830d42f69b1c0195bd65900ebe112e659432334b3468f3d0e", - "dist/2024-04-29/rust-std-beta-i586-unknown-linux-musl.tar.xz": "c8a837e0d9da8ad976fc1539541c085365aac9dd28b34e4a289d38a823d1b065", - "dist/2024-04-29/rust-std-beta-i686-linux-android.tar.gz": "f05e28a52f17e22f36ffc70018012a1fe6a07f4b461e774b36464f32bc8f8dea", - "dist/2024-04-29/rust-std-beta-i686-linux-android.tar.xz": "f9501b2691c51e54a6f4cc6fb72e41901eb551d3a7be5f82a94ce2d3e217828b", - "dist/2024-04-29/rust-std-beta-i686-pc-windows-gnu.tar.gz": "8d9a782d4f7450bca536aab45147c6ef08bc3847b43fdd171c6449e29762eda0", - "dist/2024-04-29/rust-std-beta-i686-pc-windows-gnu.tar.xz": "4008712e03fb6494eaba3d79051c5e3fdd93d4c52ae8d86cf8f344b5f051cbca", - "dist/2024-04-29/rust-std-beta-i686-pc-windows-gnullvm.tar.gz": "cfb23242e495834a3d0f7ffa3da4a0b206dcae35872b1455b11faeee5511ba5f", - "dist/2024-04-29/rust-std-beta-i686-pc-windows-gnullvm.tar.xz": "95415742c0171945ffc2b67c913ebd1330e29634af238f5ccc843a965340374a", - "dist/2024-04-29/rust-std-beta-i686-pc-windows-msvc.tar.gz": "e9354d69e39ecfac1d2928664d17d73f808256a4076b849171a9667705c0aa08", - "dist/2024-04-29/rust-std-beta-i686-pc-windows-msvc.tar.xz": "a34bb0a91170d84195f35ba52afa4c9be8a2f2706dbeea02bd6e8908e08ac65e", - "dist/2024-04-29/rust-std-beta-i686-unknown-freebsd.tar.gz": "d65f286de399ccc9e9acaf7a4dc4f885357c750231d54a144ba9a59181814f11", - "dist/2024-04-29/rust-std-beta-i686-unknown-freebsd.tar.xz": "4c93a7da70a69b2ebbac01df64af16344e523d16470b29e57237b1d0925f7721", - "dist/2024-04-29/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "1b978bfd1a9234be7ef197c8c98c5a6b625f6fbb7b0fca58695986768bdca176", - "dist/2024-04-29/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "98d4eb5b89a593c8c4f86244c9a7c737d9c18c0168aebe5923b8d9145adcf89a", - "dist/2024-04-29/rust-std-beta-i686-unknown-linux-musl.tar.gz": "dbf9b3c5b54b3eb0727f976f5632c5b0fcb2f90ac7453962d6cef20f7dae4284", - "dist/2024-04-29/rust-std-beta-i686-unknown-linux-musl.tar.xz": "f209ade093753342dda6e710ee832a538dbdaa08a24d606f9a2a1bc59b83da29", - "dist/2024-04-29/rust-std-beta-i686-unknown-uefi.tar.gz": "3c3ca7f34569b2c70c6b223754418a535dd7dfa087ab6e28ed2ec78d20065887", - "dist/2024-04-29/rust-std-beta-i686-unknown-uefi.tar.xz": "72a7cd0f430ab40d80e93f409b8e26a181010ab4bb75d151e829d51ccdcf8c62", - "dist/2024-04-29/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz": "b7dfa59bb05cf806c87854d6fce5ef0f160697052fdf6e5a0cad121499108608", - "dist/2024-04-29/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz": "88bc22f68bab3367cdfa91676418ce1ffc0ec002afb32aed7def880bdd4be402", - "dist/2024-04-29/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz": "d61019048b941064a99d19e46ff3236a88a2e8fcfb963cedd1d9d1c47963c170", - "dist/2024-04-29/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz": "7474bda08134c676d74afe5263317af3f271963d8ceaa5efbfa1b657f885c572", - "dist/2024-04-29/rust-std-beta-loongarch64-unknown-none.tar.gz": "e089c77d433d838ca02d7531d6f4a1770fb4a0568acbd96c8f43034d76f2990b", - "dist/2024-04-29/rust-std-beta-loongarch64-unknown-none.tar.xz": "364ae6c89c7a930098286e55193d2f5ee3d5ea80b7cca73046e41725f4a8a2f9", - "dist/2024-04-29/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "c17bfad87d16f3a8d26646525dc59a352718db9e7572acb583b68a18cfdc338a", - "dist/2024-04-29/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "f5c4ecef1c08d19ba6fddbd359a0ce94e46888021cae057fce969276026d086c", - "dist/2024-04-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "3e7e13b0d2e804d228e1e3a9dac0205d294ae29dcc37132f15fb1e218861eb39", - "dist/2024-04-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "ea31b7678e6f64c2f9c28a9af120be04ed6f2a25a496e40afbf6e9aa0dd20b60", - "dist/2024-04-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "f0e1b314c3d5ad1676c68c112581dce62fa06ad557cd5f61034e147b064ed270", - "dist/2024-04-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "8ab7bbea6e2f72df1286facc7d306d01809a4dd9f8901dfdec7e50b594658d49", - "dist/2024-04-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "48f6abda1c7dac185858744aa2cdc3513cdfb6552535282ee83cf9c5365573c7", - "dist/2024-04-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "d920d97f15b56ba6ea81e08b3c29dc7f44f5f30b7513c53446edf95843c332af", - "dist/2024-04-29/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "0a198a770f6e6043e923b0ab1a508fd8b190612d0370c33c8dd2c5f63b6f19dd", - "dist/2024-04-29/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "424a93313cfe2d85acf956be3d9ac71ea8e34ee61617a550ad6ff5360e1dff52", - "dist/2024-04-29/rust-std-beta-riscv32im-unknown-none-elf.tar.gz": "2e2b0a8e41f4ea774d665d6248cbc2fdbe3e582206efeb87d250786ebaad0b1a", - "dist/2024-04-29/rust-std-beta-riscv32im-unknown-none-elf.tar.xz": "2da372c091017b7096e473e5c7016a504d2e041e14173d2520086cb43e0a615a", - "dist/2024-04-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "69d3b21403181b2df14243816388169db2466477ec34bcca5693fb017703686c", - "dist/2024-04-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "281b9c20f8641a3d1b349e762b7f713fb0b91da0d21eec798e639e36a0ea3dab", - "dist/2024-04-29/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz": "dd9bfd3fd8446d35180fe781139dfb4e04dd658b112eb2a749e8f4aea14f0271", - "dist/2024-04-29/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz": "b1366375e0c5f53da581741dec91972b0c46d7d466052539207e8feaab0ba3ec", - "dist/2024-04-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "7c6650d8cf8abd51547010e8211af3ef3195099ef43a563460ad4780de20ba17", - "dist/2024-04-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "bab46f3c0078ce346de563bb7a248ca92f15dbdc73bf5a3bc520486118442320", - "dist/2024-04-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "01735b4ad5bc0a53087dd0ccaef2cf174b27e45bf4d2e3c15e64f7522f059c63", - "dist/2024-04-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "0bb272c2c235583ed3e9ec151b3bfc601f8cd07822c2fe47a1258b358be507f0", - "dist/2024-04-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "b2c7f8ee0efe6d0812e4b5dd0979f60f105b84d34d4f600ef75f2eacd954893d", - "dist/2024-04-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "0d5301fc553a6911af6643ab7f57b6438bf649ffcd050d486278c0c5fe38eeba", - "dist/2024-04-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "0d1d35ecb88ee717720ad8e74bd5b602fd6011fe321baddb939f3b161e9cd8c5", - "dist/2024-04-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "a5cf0b98596e68e6f72be2e83c61b8aaa19ead42f248ee2408a3b8f4e97a6657", - "dist/2024-04-29/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "629ed749cdae110668ad9ddbc5c61e99e8d400f3dd0981146c3820deadc360f6", - "dist/2024-04-29/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "192819438ed27a565cdb67b51d2f5caeb6ae258de86191d6922574327f132acd", - "dist/2024-04-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "84286f6cf6f00f3c92dc881f64a31e1ec5910102d8d3d4faf6fc7e2ddf1544a7", - "dist/2024-04-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "304b5f876b47dcbb7c3483c49295b822e8ba83234bb568ce67896ae4773ae2fa", - "dist/2024-04-29/rust-std-beta-sparcv9-sun-solaris.tar.gz": "25062159b859e21dda76ca22d4a31d3aba4fcdb0def78bc5b5cf9887c07c1be9", - "dist/2024-04-29/rust-std-beta-sparcv9-sun-solaris.tar.xz": "5d557ee86457f288462603fe53bcc2e092d84faee543659419fa68c1bd88f554", - "dist/2024-04-29/rust-std-beta-thumbv6m-none-eabi.tar.gz": "a9663048aad82ef832b2cf82fa9fb94be047f77e283e8aa3e2df6ad957d0782d", - "dist/2024-04-29/rust-std-beta-thumbv6m-none-eabi.tar.xz": "4c4b703a846b4123d09c1eace6322e82784a004b278f1f3b1ca1279e96207f18", - "dist/2024-04-29/rust-std-beta-thumbv7em-none-eabi.tar.gz": "32907c33f240abb1cb17ac438da42c5fa3932b270ad08fd6914775c5b59a02f5", - "dist/2024-04-29/rust-std-beta-thumbv7em-none-eabi.tar.xz": "112583227d2b6abfef6eeb78d980bf2efef392f3b66e433c4959a642d72ffc7b", - "dist/2024-04-29/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "7ba0084527a18479c4b6f6a0dba8ae23a0ed50e9fc5fbfce23cae1babb5a1e12", - "dist/2024-04-29/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "49eb4e2efe3a76713ce1fecacaf915717eeed8552912b92895c7fee068a85a36", - "dist/2024-04-29/rust-std-beta-thumbv7m-none-eabi.tar.gz": "518a532b52f2dad2825158614cd00b12aac6c6e1983a1ad53e2b0e26d1f1b845", - "dist/2024-04-29/rust-std-beta-thumbv7m-none-eabi.tar.xz": "2895e5796a29fd016462694d880e38eb191cb92c9bdb14414c1d6e63b23d3394", - "dist/2024-04-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "2af590c063344c4c3f65d704fa255232b5f5954872d03c4c55d48662cbe6bb17", - "dist/2024-04-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "a09df5f38183d9fe6116c807619f812410763ddedf06055bfe8040b5794104d3", - "dist/2024-04-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "eac22c4972bde3a57cf2ec4e31b43db3c4b7d961ae31475d8942e898c07640cc", - "dist/2024-04-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "104f2c6490e30cc47833edbd806c2efe6256d1194600b2278339612f94704d45", - "dist/2024-04-29/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "b3c9c9d7ce8c1db6f20e8ede542e67aacd6047c52882a5d06c4f96a40a7304d9", - "dist/2024-04-29/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "76bfb114bc7674792934a4892d2db41fdc8f5bd30c3aa96c43e8055199157476", - "dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "1308335fe80dcafaba511ee589959d461145533de5f76118fee29a7e9a15841f", - "dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "cb8acdb8920983c03b9495cf3506a3014384b4d2f6a53e7907924d38a0baf7f0", - "dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "9dd2e5ce7534ab4fbb93ff652196e877f4e9eea3863920c3d34a05d9a3598c81", - "dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "4b6e962facf7c54846965a8d6880e4a980804459151f2e22ac5af79bc79e26bb", - "dist/2024-04-29/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "731603392b6e3d36b3a4956928d084e293ef18c8b8593efa756e753a2a309709", - "dist/2024-04-29/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "8b681b3af47855eb63c4ffe06a2bc6bc4f365354ffbc171ce8cbd8c2a3588a07", - "dist/2024-04-29/rust-std-beta-wasm32-unknown-unknown.tar.gz": "7b87e59391493c3147c03794061111e25bdae669aea58190a951cdef111e75e0", - "dist/2024-04-29/rust-std-beta-wasm32-unknown-unknown.tar.xz": "d15eaadb101027906c2fce15b95a3f820bdbc4cf145b705bafc2ac5291289c3b", - "dist/2024-04-29/rust-std-beta-wasm32-wasi.tar.gz": "07390ec742b79ec11b2c3ec65f60efe5d7c616f50c33058fce346f6e9ad21af3", - "dist/2024-04-29/rust-std-beta-wasm32-wasi.tar.xz": "79e34d46621c298cadb98c00ce3b25d97474aec300d85255153b47e21b7bb744", - "dist/2024-04-29/rust-std-beta-wasm32-wasip1-threads.tar.gz": "b916dc9051b0278f820ea0b093db3ecae2e27de641ef67a9b508df75dc92c938", - "dist/2024-04-29/rust-std-beta-wasm32-wasip1-threads.tar.xz": "2867922a39da3b02ebdb93fb78b010695daf468f87485ad8ab79c7f3eeb18b11", - "dist/2024-04-29/rust-std-beta-wasm32-wasip1.tar.gz": "792b718c0a72e97ba85a17ba67ee09e55b85de829fe4021f828ce54ff8cb31e0", - "dist/2024-04-29/rust-std-beta-wasm32-wasip1.tar.xz": "abff86499119bddfeda9059004549941dbcd3d911702d4a9c198b94f60e60f4e", - "dist/2024-04-29/rust-std-beta-x86_64-apple-darwin.tar.gz": "0bcc7698efafb42a37f20815f5660e39829a42a2776304e7129d0a4ec0c7520b", - "dist/2024-04-29/rust-std-beta-x86_64-apple-darwin.tar.xz": "c437626e250b0d06c05dc828ab81d0d2c543ffce4b100567910508974ea50045", - "dist/2024-04-29/rust-std-beta-x86_64-apple-ios.tar.gz": "7c98c9f491bfc837111769a45c10ce2f1ef73c22377158ef9ae80b38034892c0", - "dist/2024-04-29/rust-std-beta-x86_64-apple-ios.tar.xz": "f4bda724e6e382e02ddf4e4e7a479120420666a5a1ad3c87a85d4d3c763f2cb2", - "dist/2024-04-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "01efbb2e48045318e18bfc7b6c190b461a219e81fc1cca6c855bf0c658aef556", - "dist/2024-04-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "9bff316c6d2fbb3c0889f9ffe4eae496b293fb3afaf8d597155e6badbf0c6a8e", - "dist/2024-04-29/rust-std-beta-x86_64-linux-android.tar.gz": "5da713547a8af2c86da7db5d8aa4c27188dea1089fded81ffbbeb0f78952a10f", - "dist/2024-04-29/rust-std-beta-x86_64-linux-android.tar.xz": "9d6a45d6af395360c63ce97bcfc2f9a2967c708afcd979f17fa447239703a92b", - "dist/2024-04-29/rust-std-beta-x86_64-pc-solaris.tar.gz": "d1a71110bee002c8edfbcc00e0f5eede5afa005b09944bb2cde469c658049e70", - "dist/2024-04-29/rust-std-beta-x86_64-pc-solaris.tar.xz": "6b8d18c83b9fffdddf9e55c807dc7d5784cc6d7ae90a57c29b87d707f0656964", - "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "28921ee14426f54aa09523547516437130654b2d9814120d286f209666c88533", - "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "7c3125cce30978ca2619e9aab150cb5b9b2535fbb6274d4ac1b1d4342c7b0220", - "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz": "ee5c237f092f8a4ba797c4c7769dfd4da81b5c86d2f4b88704d127642d222a22", - "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz": "30c84b04bd2d4d33abf1875cfee5f227ef6484edc67b3cc4c9c96d92c8406d6f", - "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "81274050e72c5a8ffdead83f7be62434f35a65517a1b3c6f7d9d14d0d59da710", - "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "215e20c78a2a4edf9b8368a29a09af5f4cf8d0edd1995de3bbf2eff01127cab7", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "340131cba121827a9753e19cb3a4b9ba2ebe30569fb20d7f9300b4dbe2a15cf4", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "69626178bc5309afc8a02c941bd77e70e1aa6917ffb6bf0d67a57d921b5c664a", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-fuchsia.tar.gz": "22c6c90533dad3a731ad8a6696e6cdc1b15579e25c658fa2b094185e1893934f", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-fuchsia.tar.xz": "30d7ef6684fa98e28037b69d4220cba40489c23e80fe7793c98b388dc161757d", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-illumos.tar.gz": "9d7192d32eaa6b6ccb0f615da0f4cd80827ba6484eabeaf401d8217678f1e313", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-illumos.tar.xz": "7a3fb35e0bb252d5f90773136d1417c26d5601beadb77d6da6f5ad3081977f07", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "e987635519c1edc8a1d147ca4a86283637e4dbd0a49736b01d605e45a3a14e8f", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "c3ab6b97dccc0038c68494b03b6d444d534e447226a2b2e140af54c94fca0b2d", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "72e8113687be8f947c50befb42b0957dd564f01693cf4d68d749a9e074032ada", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "867b24f33b19f40727c71818c8a002718d44d4cd4ceca44314331e19c1adc1a4", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "f9b0fd9605bd4e264f5303bd740d9a0195bc147132969965b221f9da0d7875bf", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "022dcf4887df41d776ba2666858b9aaab479758134a71f7c6b2172ed7c1a1752", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz": "b5ff4a0ecd7e0f71a9557b6096bb907e5cbc8982431f0d9b01d8e1a895d8b37e", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz": "e40d5bfb46aadf6faf849df548154db3f35f356f8b98037a056802a235922b8a", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "57cfb1fa472dd9c01fc0caf605a55b7248375d616acf84ec12f6430d5e07e2ee", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "e4121f060b917c811d971e85ce02495e83150ddcceb2204615edff24bd55bfa6", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-none.tar.gz": "d63559803c8eb47e0d10d9f3a2284477b570a2536bb541762774271451e1f0ce", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-none.tar.xz": "5388cf8ecaa234d507e505e8c6d433c5de8811b2717aa254e4caac9f4aa6cd97", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-redox.tar.gz": "0f027163f37618df4330ecd82afece432b0a509ab20333d7b787c0d139ea89c2", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-redox.tar.xz": "b1c722e894b145c2183183fa58762c64402fac077419dc7874f8b08eee665651", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-uefi.tar.gz": "24e2ac0d44619ef9b76cb1af6178103d65ab12e2677b366e8aee0604798fe5f1", - "dist/2024-04-29/rust-std-beta-x86_64-unknown-uefi.tar.xz": "1d8a45f1bfe6650edc5ddfc8683190eff5a74384abcb2f73eb3d1e88d566ccfc", - "dist/2024-04-29/rustc-beta-aarch64-apple-darwin.tar.gz": "ea113c567692d54983ab6c376761651b6dcf9bedad5b5d822d28c0d0d0733cf2", - "dist/2024-04-29/rustc-beta-aarch64-apple-darwin.tar.xz": "e36363f1ea531d2fd563f471758e387de37a34e7ef6f4c12175979657333c5b4", - "dist/2024-04-29/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "52d77d540fc3f83d82f35f358ccd9055fb75453af3e3bee4b11636742559db13", - "dist/2024-04-29/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "843c56f5431c1feda85ceaeef0daf988e8ae020b3556326fb1f75ea7968bf2df", - "dist/2024-04-29/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "ba2fe37dda1a487a2c75151895f4f6e886e9476a992272ce26e9b5fd7adb11f9", - "dist/2024-04-29/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "ccb7be3935de1920509d2061d38f92f1fb8d2a5dd6cef392492242a929363fa9", - "dist/2024-04-29/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "40636e0936bd311803317825c5fb6b446cdb5536ada1db097b567df04a86d7dd", - "dist/2024-04-29/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "804ef68f24bc0ba5150177d8b8515daa54aa82fcb61472385ef1a1d897c5c3e1", - "dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "a320c2869d1d2c92b698397d4467c8498cad9481f38d28ac810bd165399ca46b", - "dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "7ce92211d87068d9c223806929adc34ca611a1321cd58b5bd81aabb0ec3ff085", - "dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "79c16b902884301882d16be36fe75ecb32a8e49abde0038ce21cfbee883c2c3a", - "dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "9384eb9bdbb585b414b6c04c592a79e90a0c0ebfeeb970e5e1b920cb638807cc", - "dist/2024-04-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "ff99de5b819a4fb9adce9386a309b9841bd33632eb7d5079415a6ca6fc86b9dd", - "dist/2024-04-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "55635cde13af11dd8cc007d2e0499bfee493bdfba87b6efd7b1fa4115f5728dc", - "dist/2024-04-29/rustc-beta-i686-pc-windows-gnu.tar.gz": "de82ac745275f069225b84574ed145afaf9f54abde5246592e49d5d1cf40cac1", - "dist/2024-04-29/rustc-beta-i686-pc-windows-gnu.tar.xz": "a8a7bf64d33c95a2f94265fba8dd9ac50bbb727f4bc3e79be5bf61212cb5d22b", - "dist/2024-04-29/rustc-beta-i686-pc-windows-msvc.tar.gz": "88967a99c993d6e0c3c7948308510644286ac826266dbd3d89aaa083100711db", - "dist/2024-04-29/rustc-beta-i686-pc-windows-msvc.tar.xz": "1804f75786482946258ff0e827274357c49e90a7f2f568add7353249f2ab78b9", - "dist/2024-04-29/rustc-beta-i686-unknown-linux-gnu.tar.gz": "3cb7e02c61d4a21d8289289b874b25e8b020c1d553e5af950160bffc14f51c18", - "dist/2024-04-29/rustc-beta-i686-unknown-linux-gnu.tar.xz": "2ad4b1311a0e39c359798375912faa91b4e13cd473bd59efd1e4f721777d254f", - "dist/2024-04-29/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz": "ab19efb741a127615b9022dedf1d895b53c69740cc3da745f9b9888bade9d98b", - "dist/2024-04-29/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz": "492cc11d54df410c2547890803930fc65950e6b81ced512e24bef56c3e70f3d2", - "dist/2024-04-29/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "c5a631a41f417336f3f65c85adefd1fb0bacc02465485f37d29fc1223c9f6cec", - "dist/2024-04-29/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "0701183b615d9eec9daea724d4cd8fa98dede2260cfb6b137d6cbf8ad6b29a4f", - "dist/2024-04-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "cb70e92d5275862b500614d79eaea3d19319b96798f4850cb19dea9a8038a651", - "dist/2024-04-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "908cbe562d82cca1bf176fdc99af867966ea423d244c4a50e14bad19f6878201", - "dist/2024-04-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "8580a3eb6d6df1774f4b6ca06dc1195c42b1e2a463488a5d851e99b0ca6d0249", - "dist/2024-04-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "2627948036e905f2e280663c56c86c172e2b0d057311ade7ca238953b7e0c36a", - "dist/2024-04-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "526e4f129fdb4b2c8f4317c57105a09ff03e71771d6d6bbbc9380917b5440d71", - "dist/2024-04-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "fd9dcf60838376478d7cc505ec7fc39f86f9d042646a3b836e9c06825927c7eb", - "dist/2024-04-29/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "664c1255a9435d1ad086329a3c215974b9302d481762240cc9d0328d9f1b8c9a", - "dist/2024-04-29/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "a585ce7684e4174f03adb09df17221e1729e8179dbc91b9a0f8813c3ecc0822d", - "dist/2024-04-29/rustc-beta-x86_64-apple-darwin.tar.gz": "59a1d91009b506a5bce3c276993cb8acfd71f73d01f9eaf4195b36114ac822c3", - "dist/2024-04-29/rustc-beta-x86_64-apple-darwin.tar.xz": "f86f3309cf2784b076f14e7da9e921c294a7701ea92d378c609061deccbc6bff", - "dist/2024-04-29/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "f5c074461409b33a9791325d4014e6861ad36f99b9e48e54ecceb73986450be1", - "dist/2024-04-29/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "045431eec6f839b1c40b5a75c5000f80bd6351274a59b29d962833495324ecb6", - "dist/2024-04-29/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "a3abfb68e60544170f47209bbf048f1374e5bb75901a529e2ac2f315758155f8", - "dist/2024-04-29/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "398c41a3219781c7cf1a907406506526b672abca6d3ab59c30556390a5f992c9", - "dist/2024-04-29/rustc-beta-x86_64-unknown-freebsd.tar.gz": "38895e615efd0bf75ca14b0ab0a085527cca64fae17631d1780a8f51acd26d17", - "dist/2024-04-29/rustc-beta-x86_64-unknown-freebsd.tar.xz": "786f40030dbe5e6897aafe4bda44770920b2010b93fc5ce86574774e531e2eff", - "dist/2024-04-29/rustc-beta-x86_64-unknown-illumos.tar.gz": "7003cab7650dae7e3d29032422a57782a2c146024c437a6466ae1dd2b61a6618", - "dist/2024-04-29/rustc-beta-x86_64-unknown-illumos.tar.xz": "bed3cc10203e8bd4d43b6245928c8a607acc5b6e633635caea45eb4eef4bda56", - "dist/2024-04-29/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "84cdea91c9f1e848ea17f554229ca80d18d093fc609641d8f003c4f2d4871866", - "dist/2024-04-29/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "a20fce7512f7c8cc6230a0f63f12855b04370d25e621183f71aa444c90c36b4b", - "dist/2024-04-29/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "87e0c484ade99efab57c655ef96dbabf7a02314540575b65a14372ab5496c36c", - "dist/2024-04-29/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "469757d8f35c9f4210aefd2ba660ee249e4409d47b908a6c68c1e650ee81ae67", - "dist/2024-04-29/rustc-beta-x86_64-unknown-netbsd.tar.gz": "4a38000480fe78fd5da7f9b71d36f296a6ae103254d932c4de6b902354e86bbf", - "dist/2024-04-29/rustc-beta-x86_64-unknown-netbsd.tar.xz": "45945d6af237fe4c91fde7db02ca19e99bac56a911b8db79be9b6ab8bb3934e1", - "dist/2024-04-29/rustc-nightly-aarch64-apple-darwin.tar.gz": "0b07375a9a6507fd4932a05b5aaf28ed349fe2040103f1cb69c8a2494437258f", - "dist/2024-04-29/rustc-nightly-aarch64-apple-darwin.tar.xz": "143bd7ed3ca7b913ddd0cea7cda8d1a0e4c29cc2ccbb7d29f0e45c2a87c3ec46", - "dist/2024-04-29/rustc-nightly-aarch64-pc-windows-msvc.tar.gz": "9404c111b91fd092367b88adbc37dce10a98c443bd8d9e13a860e1fb4e3af96e", - "dist/2024-04-29/rustc-nightly-aarch64-pc-windows-msvc.tar.xz": "f9f432907c276edcae5ad8ade0264f3c03109be02e791a814edc8ad3d229637a", - "dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz": "33425c90427424f0b30fa2a6331a3b59c680f1c1bd0d8845d7e6bc1e2f80292d", - "dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz": "03792890c64c72f30143849894b15f0eb3d6ad735fceede9092abd900ee733e4", - "dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-musl.tar.gz": "cf6f2bffa0db1b4b9b8e95801bf415dcce413f902e26f4c1831dff1a00752b99", - "dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-musl.tar.xz": "9192fdb668df8d4cab776623db7d01e35af42fea94098c1d4ba53190825d81a8", - "dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz": "a174e7e08da2abc6b84499360670188f5cc61b6d055967e04bf602ff3d831f45", - "dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz": "5a59811027586863852b15fc2b603e7e69b19841f4c10d2527ef1fc5b77d8af2", - "dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz": "645bb5dd7a96bb9292b9956cb9705e9aed2408e47728f245564f1f7404ede783", - "dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz": "1fe34911b082c3a5ca4f24656675c095d2cf56f8005be9ca2517d0ef7d0a2b37", - "dist/2024-04-29/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "f2d6403d81bb0afe2e14956828987a0bb044c95f2d9566e1d792dd922dad7914", - "dist/2024-04-29/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "d93fdafcbbfd50c88c3f4feb4c68b053882ccae02c45e1615aeeae5a86f4aa98", - "dist/2024-04-29/rustc-nightly-i686-pc-windows-gnu.tar.gz": "a9e997b03559b3dfa2a0eba6ed7a142d7651ea7f4ba4e788d9de807b50558e58", - "dist/2024-04-29/rustc-nightly-i686-pc-windows-gnu.tar.xz": "4412b5fbfab8c5b31e57cf8c4ce9a9d13cfc9c0a8174ea1fc8a7c05281e1cb54", - "dist/2024-04-29/rustc-nightly-i686-pc-windows-msvc.tar.gz": "1725c41500dbf6bea554f3d4acaba70167f0e89087aaa3eb3c0f8a99047c55c4", - "dist/2024-04-29/rustc-nightly-i686-pc-windows-msvc.tar.xz": "27db022494afebbe05605f134191e8b2e78bfdeaa638d4215174038ca9dd2fd7", - "dist/2024-04-29/rustc-nightly-i686-unknown-linux-gnu.tar.gz": "dc1a05d49b773dba06808c1c50653ecac506b3433f0f6dfa307109a7c621cc1a", - "dist/2024-04-29/rustc-nightly-i686-unknown-linux-gnu.tar.xz": "cc58ce3af8f5481ada4dc129079cd558664717526b2f7f9a02bde6bafb6f45ad", - "dist/2024-04-29/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz": "34cfe803126ae9218b17adfe833a55c697dfa50729ac83b642529f3682d12d15", - "dist/2024-04-29/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz": "c752dc8962656c09047151fd24166f3134fbeed85006b5d22496691079c7fb9c", - "dist/2024-04-29/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz": "386b086b8aad922050c813dd58bb79a52ef806b2d1413e2e9cc46d6e43b81d7c", - "dist/2024-04-29/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz": "d9eec9ab7c265444ac5f04d4ec9e77d4c0c3c2e34c5804db8abf5f94c8fd2272", - "dist/2024-04-29/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz": "91df129046443554bfb836d25886aa9807b917acbc9dcf30f6531cde7bf912fa", - "dist/2024-04-29/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz": "ca9b574b9f2e914b5a6d9e011aba805d1e6f9b687dc1a1868e88f0e4d9e4401c", - "dist/2024-04-29/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "8b44f96a1ccd6d501b0af3960edb2c1a6c93957676a1c2cdb831e614de398f8b", - "dist/2024-04-29/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "f8a10a6767b80bf24f73223b9e46e1b18b6bf6746ad2115eb8968a0e482f0e4e", - "dist/2024-04-29/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "a197208807503a9cfbc6df938d614a192da48884b2e4892f7b1d234579091be1", - "dist/2024-04-29/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "af3a1a33942bd8a3417593dc118abb1db0373f5410f54771713c05bb86724fed", - "dist/2024-04-29/rustc-nightly-s390x-unknown-linux-gnu.tar.gz": "5a3a3aa73b6a0f21c63b9a40bdbd0bb4dc59bd75add0a06e292ced791fad31be", - "dist/2024-04-29/rustc-nightly-s390x-unknown-linux-gnu.tar.xz": "6d7903f1c9fc95a23448717326d667dce59e54aaff821443d3cd9137cf3537fb", - "dist/2024-04-29/rustc-nightly-x86_64-apple-darwin.tar.gz": "64eede54da4bf88b0a42ecf7f7a4bf8002b5550e60a64e1e48244c7f5b04768c", - "dist/2024-04-29/rustc-nightly-x86_64-apple-darwin.tar.xz": "0a8f95e3bb0bebf9bcc8116b91bab3ba97cb6ff4021713586280aaceed9da030", - "dist/2024-04-29/rustc-nightly-x86_64-pc-windows-gnu.tar.gz": "58f9e0dd9c1aadde2dfd869528adadd4acc29ab0850236f3cee5f023d4211939", - "dist/2024-04-29/rustc-nightly-x86_64-pc-windows-gnu.tar.xz": "a211a962093e0d09358d51a6eb48da0966a02383c6b00c8acc077b5663d7d707", - "dist/2024-04-29/rustc-nightly-x86_64-pc-windows-msvc.tar.gz": "5631926874dc54204c319137a77a89de5e6f408de2a832109e2be71ea79f27d1", - "dist/2024-04-29/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "a8cf87bc663b5e3dbcc97b0eb58bb1b9b5b0100aacb47dc0c372fe1612517244", - "dist/2024-04-29/rustc-nightly-x86_64-unknown-freebsd.tar.gz": "1011f98197a9fe82d6095f4521934a06eea5f7e9719a6e4c9e3bf13d68f799ca", - "dist/2024-04-29/rustc-nightly-x86_64-unknown-freebsd.tar.xz": "79599b3f91f9372262e97a417f4e104ef5192c0f6f8df204aea9c8b3ee39430e", - "dist/2024-04-29/rustc-nightly-x86_64-unknown-illumos.tar.gz": "7179a453bdcb17e401c0af8f4ab86cb5a4752a8ec80b0cbdd4cf1854c7f36a35", - "dist/2024-04-29/rustc-nightly-x86_64-unknown-illumos.tar.xz": "d565fc366fdbc305fbfe59e72b971c58f201d69e03a9ffa667d2ca0735cdb7f3", - "dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz": "ae6bd8e20560d48519290d78e3d21f84b983403ca1f8f466a85496276d7866da", - "dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "c7c0f8f44b0275456a27952178caa04c32eb9a1507056ddc05926a0730e17359", - "dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-musl.tar.gz": "3246797ddbc9118de819b13b005b83748338f3c825a7436ebd5aa79ca55539c0", - "dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-musl.tar.xz": "c7e784e77dbabedad88d24d2ae6dc4abb68bc04b1cd6c9d45f6dc28b6d0e2edc", - "dist/2024-04-29/rustc-nightly-x86_64-unknown-netbsd.tar.gz": "c9452de4b3f15f0cf0b7d737b217b2cc7b88a96543bd8ce587ee14be1e21a90a", - "dist/2024-04-29/rustc-nightly-x86_64-unknown-netbsd.tar.xz": "de9b05278a5c69d53ccbb31223526ea2aa2275c0fb3f046d1c1b4d67c0b0c275", - "dist/2024-04-29/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "3734353a58dbf6c3831cc6b4ea606357140c191c89e8dfca1d7aa2f3fb8ac53d", - "dist/2024-04-29/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "e5e3a6e609fbfd537aa4acfefd3681d4b6c8029e2801a1ef23e8b09cf5a47bfe", - "dist/2024-04-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "22f54857e01d759301d099b67547cdc485596499088d0d749d38058c28e0f752", - "dist/2024-04-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "db48a9d45dc7c7aad4c9bb0d20789dd35fb6ef7a966948c44fbbae132de4c16b", - "dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "fa5d1fb9f3627e7d59269a1f8008d780c685ea04975473f1808287134e7bc5a7", - "dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "61ab625b47fa9097af90a79a1e75a2f2492a415f4009c9043cf453bd4128f031", - "dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "cc79969341fc60991059d0e3f13a69489c1e0915ea5787a88b8605ed5b7f3cd0", - "dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "bbdb75f922b4b1716b033d91c76c4c0aa53061d6e7fa53a9bf16fe076814bbb2", - "dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "13ca68afc3f3970a37951504664b58035102e1ae06d10a744389603b2f7499f5", - "dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "04b174aa724945b6359a555892506c6a742a7c427464e8206433bb3f9a65fc02", - "dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "430333380a590a9de211c8d735989fedb89321cf9f5f9a0b1ef651ec8b598691", - "dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "924713e648806945cd56e54d4c11dc74b65241c8dbf6cc7b401c5c93d0f7ffdb", - "dist/2024-04-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "bb6e5a8b5cc88099e613aa5f4d926165976d8e4a7fccbecf4ac3b0eb966d7a0f", - "dist/2024-04-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "34d5e970304e1734aacb26c095e926c27a07e1a41fe70db9fa2997bef97ad3ec", - "dist/2024-04-29/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "835447a1d9d60659e99903275f327641809fc0148f35149f980d1a17ff87cc9a", - "dist/2024-04-29/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "ddd84a7f900aa239f93711f7da71e57aaedeeba2c9c8a8f23608acc7e48613c0", - "dist/2024-04-29/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "02f0af2bdae167c6091099a9b54ceb150c22b0f20dc861587a02cac78deb0b39", - "dist/2024-04-29/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "822f78f39dcbe3282bf7888a8cdae04efe7b023ded026a7e7f430e4ff15e7942", - "dist/2024-04-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "68a6189652c11a2c142c5339e2f5fb09d5f3e85d860bff063f62d5d3a3d111bf", - "dist/2024-04-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "6740ea882effa2fb87dd72744c08888ce5ec59c9797c00369156b24847bb180e", - "dist/2024-04-29/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz": "0bb365e2d895ef3c39c4899a01187a23f9b7c5195c30bf845da3917f62f5eafd", - "dist/2024-04-29/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz": "2e54c9887bc6ed1eb09b9f69c8425da843ea12bf33248fa0ccdc0d14387c1c57", - "dist/2024-04-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "b0c0fe437921d17e2f50cbff87beeac067efa3d5211a241fb6f4c10b8ab500ac", - "dist/2024-04-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "64e7282c0cf4a714b11eed1d28be3a64ba0ccc6d899211a872a5a7809d514c08", - "dist/2024-04-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "100cfde057c81460b8cfde2047fe83ddde360a6df1ff178da5a968b17ecc9df8", - "dist/2024-04-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "38e8712e98fa0bc6962ab2fd2e3b96a2a5dcaa6c16161d8caf71131a1ca5031e", - "dist/2024-04-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "4dab52b50e19348fb39fdad39ab44189c27c10f80b5fbe2cc4723b644611fa87", - "dist/2024-04-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "36d1b2c9150fafc5976c296200ba3fac3e923df3e6f18032068200e2a887146c", - "dist/2024-04-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "7cb4a536320c23d305ce3bd3b7a954d951bf4d358ef3732be75b9b290c4818a5", - "dist/2024-04-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "ede1afc7dc5892ef6f780e987737e145c4b4d00495da8c2e9902182a3a174e20", - "dist/2024-04-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "e2d2d561cbfa0add0e5349682976216d3a7cff4094372c1ed26854bb4e4d93fd", - "dist/2024-04-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "e0380e65e83e4131f6aa7ee4e185689add4372b0c1653312e2ffd56072fdd0fe", - "dist/2024-04-29/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "73a140c7ed9c80f209ff976c63b0a34d625d651553c38692c91f048f4e0ae470", - "dist/2024-04-29/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "9946b7120465181e05916b8023bc075b32bd85cf45a3b1d8bfba2f94ac78d927", - "dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "eda273f27714b1e45adcc2388149f48de0e32a9104db0b9d1a02f6d37de43fef", - "dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "f2955a4b696d050c219a96c093162b42a2fab921f9f3cb7570f8462928306c6d", - "dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "ec900cc2d3c6d45ef039653f4418f9b9a4a5fddd5d7e8077c3fb08b36c539a28", - "dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "04e6999a3405acc79f5fdcafeeab52880e5eeeedd3909b5f3c57e7647c86ef99", - "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "0730c5ebd576fec5371085f9fac0adde9424e1d7626456ed33bc66351b0ad307", - "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "90cbd84b8d48f0235a1954166f5edd53dc3031532ec6dfcb364f9a9624c9ce11", - "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "5f5c62d321db27eb495f6ea312ef8bea0bf17a7a501a44e062986c416951700f", - "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "a3bf64e2f22436e4484fc818f69d2f750fddd05a96463fd4abfcf655edce36b9", - "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "a847a6f9c7a3ce71c7cd8d81bdfcfcd8e4d128aa28ba0dafea89b0cc37c6c36c", - "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "21fa794456566c64d08f629a385f89b3cfe9d9b69f317ae85fbe7425419108ff", - "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "b3f792f10a98993b4b55d1df951727a4422102d51b1145e51824268d48587ad0", - "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "d791f0ec3c004e7baa0381962bf8ca2f18a3c861152702de5301d0149260e7fa", - "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "9807b2887e976d29f0c04484f8459175b4f6b70ef000037cdc4dada48e3cbd74", - "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "019920d64778af62879e2146c2c13d9f6e2165a38bbfa1982694bfb48864d308" - } -} diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index f3972346bb5be..bed76263b4516 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -236,7 +236,7 @@ fn main() { let num_threads = if let Some(num) = env::var_os("BUILD_MANIFEST_NUM_THREADS") { num.to_str().unwrap().parse().expect("invalid number for BUILD_MANIFEST_NUM_THREADS") } else { - std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) + std::thread::available_parallelism().map_or(1, std::num::NonZero::get) }; rayon::ThreadPoolBuilder::new() .num_threads(num_threads) diff --git a/src/tools/build_helper/src/lib.rs b/src/tools/build_helper/src/lib.rs index 575f3677155e5..6a4e86eb1dfe5 100644 --- a/src/tools/build_helper/src/lib.rs +++ b/src/tools/build_helper/src/lib.rs @@ -2,3 +2,4 @@ pub mod ci; pub mod git; pub mod metrics; pub mod util; +pub mod stage0_parser; diff --git a/src/tools/build_helper/src/stage0_parser.rs b/src/tools/build_helper/src/stage0_parser.rs new file mode 100644 index 0000000000000..ff05b1169895c --- /dev/null +++ b/src/tools/build_helper/src/stage0_parser.rs @@ -0,0 +1,76 @@ +use std::collections::BTreeMap; + +#[derive(Default, Clone)] +pub struct Stage0 { + pub compiler: VersionMetadata, + pub rustfmt: Option, + pub config: Stage0Config, + pub checksums_sha256: BTreeMap, +} + +#[derive(Default, Clone)] +pub struct VersionMetadata { + pub date: String, + pub version: String, +} + +#[derive(Default, Clone)] +pub struct Stage0Config { + pub dist_server: String, + pub artifacts_server: String, + pub artifacts_with_llvm_assertions_server: String, + pub git_merge_commit_email: String, + pub git_repository: String, + pub nightly_branch: String, +} + +pub fn parse_stage0_file() -> Stage0 { + let stage0_content = include_str!("../../../stage0"); + + let mut stage0 = Stage0::default(); + for line in stage0_content.lines() { + let line = line.trim(); + + if line.is_empty() { + continue; + } + + // Ignore comments + if line.starts_with('#') { + continue; + } + + let (key, value) = line.split_once('=').unwrap(); + + match key { + "dist_server" => stage0.config.dist_server = value.to_owned(), + "artifacts_server" => stage0.config.artifacts_server = value.to_owned(), + "artifacts_with_llvm_assertions_server" => { + stage0.config.artifacts_with_llvm_assertions_server = value.to_owned() + } + "git_merge_commit_email" => stage0.config.git_merge_commit_email = value.to_owned(), + "git_repository" => stage0.config.git_repository = value.to_owned(), + "nightly_branch" => stage0.config.nightly_branch = value.to_owned(), + + "compiler_date" => stage0.compiler.date = value.to_owned(), + "compiler_version" => stage0.compiler.version = value.to_owned(), + + "rustfmt_date" => { + stage0.rustfmt.get_or_insert(VersionMetadata::default()).date = value.to_owned(); + } + "rustfmt_version" => { + stage0.rustfmt.get_or_insert(VersionMetadata::default()).version = value.to_owned(); + } + + dist if dist.starts_with("dist") => { + stage0.checksums_sha256.insert(key.to_owned(), value.to_owned()); + } + + unsupported => { + println!("'{unsupported}' field is not supported."); + } + } + } + + stage0 +} diff --git a/src/tools/bump-stage0/Cargo.toml b/src/tools/bump-stage0/Cargo.toml index 4680a7ab66107..de5d821133d53 100644 --- a/src/tools/bump-stage0/Cargo.toml +++ b/src/tools/bump-stage0/Cargo.toml @@ -7,8 +7,8 @@ edition = "2021" [dependencies] anyhow = "1.0.34" +build_helper = { path = "../build_helper" } curl = "0.4.38" indexmap = { version = "2.0.0", features = ["serde"] } serde = { version = "1.0.125", features = ["derive"] } -serde_json = { version = "1.0.59", features = ["preserve_order"] } toml = "0.5.7" diff --git a/src/tools/bump-stage0/src/main.rs b/src/tools/bump-stage0/src/main.rs index bd97b4eaa3e4d..bb06e113c0e94 100644 --- a/src/tools/bump-stage0/src/main.rs +++ b/src/tools/bump-stage0/src/main.rs @@ -1,15 +1,17 @@ +#![deny(unused_variables)] + use anyhow::{Context, Error}; +use build_helper::stage0_parser::{parse_stage0_file, Stage0Config, VersionMetadata}; use curl::easy::Easy; use indexmap::IndexMap; use std::collections::HashMap; -const PATH: &str = "src/stage0.json"; +const PATH: &str = "src/stage0"; const COMPILER_COMPONENTS: &[&str] = &["rustc", "rust-std", "cargo", "clippy-preview"]; const RUSTFMT_COMPONENTS: &[&str] = &["rustfmt-preview", "rustc"]; struct Tool { - config: Config, - comments: Vec, + config: Stage0Config, channel: Channel, date: Option, @@ -35,37 +37,64 @@ impl Tool { .try_into() .map_err(|_| anyhow::anyhow!("failed to parse version"))?; - let existing: Stage0 = serde_json::from_slice(&std::fs::read(PATH)?)?; + let existing = parse_stage0_file(); - Ok(Self { - channel, - version, - date, - config: existing.config, - comments: existing.comments, - checksums: IndexMap::new(), - }) + Ok(Self { channel, version, date, config: existing.config, checksums: IndexMap::new() }) } - fn update_json(mut self) -> Result<(), Error> { - std::fs::write( - PATH, - format!( - "{}\n", - serde_json::to_string_pretty(&Stage0 { - compiler: self.detect_compiler()?, - rustfmt: self.detect_rustfmt()?, - checksums_sha256: { - // Keys are sorted here instead of beforehand because values in this map - // are added while filling the other struct fields just above this block. - self.checksums.sort_keys(); - self.checksums - }, - config: self.config, - comments: self.comments, - })? - ), - )?; + fn update_stage0_file(mut self) -> Result<(), Error> { + const COMMENTS: &str = r#"# The configuration above this comment is editable, and can be changed +# by forks of the repository if they have alternate values. +# +# The section below is generated by `./x.py run src/tools/bump-stage0`, +# run that command again to update the bootstrap compiler. +# +# All changes below this comment will be overridden the next time the +# tool is executed. + "#; + + let mut file_content = String::new(); + + // Destructure `Stage0Config` here to ensure the stage0 file is synced with any new + // fields when they are added. + let Stage0Config { + dist_server, + artifacts_server, + artifacts_with_llvm_assertions_server, + git_merge_commit_email, + git_repository, + nightly_branch, + } = &self.config; + + file_content.push_str(&format!("dist_server={}", dist_server)); + file_content.push_str(&format!("\nartifacts_server={}", artifacts_server)); + file_content.push_str(&format!( + "\nartifacts_with_llvm_assertions_server={}", + artifacts_with_llvm_assertions_server + )); + file_content.push_str(&format!("\ngit_merge_commit_email={}", git_merge_commit_email)); + file_content.push_str(&format!("\ngit_repository={}", git_repository)); + file_content.push_str(&format!("\nnightly_branch={}", nightly_branch)); + + file_content.push_str("\n\n"); + file_content.push_str(COMMENTS); + + let compiler = self.detect_compiler()?; + file_content.push_str(&format!("\ncompiler_date={}", compiler.date)); + file_content.push_str(&format!("\ncompiler_version={}", compiler.version)); + + if let Some(rustfmt) = self.detect_rustfmt()? { + file_content.push_str(&format!("\nrustfmt_date={}", rustfmt.date)); + file_content.push_str(&format!("\nrustfmt_version={}", rustfmt.version)); + } + + file_content.push_str("\n"); + + for (key, value) in self.checksums { + file_content.push_str(&format!("\n{}={}", key, value)); + } + + std::fs::write(PATH, file_content)?; Ok(()) } @@ -76,7 +105,7 @@ impl Tool { // On the master branch the compiler version is configured to `beta` whereas if you're looking // at the beta or stable channel you'll likely see `1.x.0` as the version, with the previous // release's version number. - fn detect_compiler(&mut self) -> Result { + fn detect_compiler(&mut self) -> Result { let channel = match self.channel { Channel::Stable | Channel::Beta => { // The 1.XX manifest points to the latest point release of that minor release. @@ -87,7 +116,7 @@ impl Tool { let manifest = fetch_manifest(&self.config, &channel, self.date.as_deref())?; self.collect_checksums(&manifest, COMPILER_COMPONENTS)?; - Ok(Stage0Toolchain { + Ok(VersionMetadata { date: manifest.date, version: if self.channel == Channel::Nightly { "beta".to_string() @@ -106,14 +135,14 @@ impl Tool { /// We use a nightly rustfmt to format the source because it solves some bootstrapping issues /// with use of new syntax in this repo. For the beta/stable channels rustfmt is not provided, /// as we don't want to depend on rustfmt from nightly there. - fn detect_rustfmt(&mut self) -> Result, Error> { + fn detect_rustfmt(&mut self) -> Result, Error> { if self.channel != Channel::Nightly { return Ok(None); } let manifest = fetch_manifest(&self.config, "nightly", self.date.as_deref())?; self.collect_checksums(&manifest, RUSTFMT_COMPONENTS)?; - Ok(Some(Stage0Toolchain { date: manifest.date, version: "nightly".into() })) + Ok(Some(VersionMetadata { date: manifest.date, version: "nightly".into() })) } fn collect_checksums(&mut self, manifest: &Manifest, components: &[&str]) -> Result<(), Error> { @@ -143,11 +172,15 @@ impl Tool { fn main() -> Result<(), Error> { let tool = Tool::new(std::env::args().nth(1))?; - tool.update_json()?; + tool.update_stage0_file()?; Ok(()) } -fn fetch_manifest(config: &Config, channel: &str, date: Option<&str>) -> Result { +fn fetch_manifest( + config: &Stage0Config, + channel: &str, + date: Option<&str>, +) -> Result { let url = if let Some(date) = date { format!("{}/dist/{}/channel-rust-{}.toml", config.dist_server, date, channel) } else { @@ -180,42 +213,6 @@ enum Channel { Nightly, } -#[derive(Debug, serde::Serialize, serde::Deserialize)] -struct Stage0 { - config: Config, - // Comments are explicitly below the config, do not move them above. - // - // Downstream forks of the compiler codebase can change the configuration values defined above, - // but doing so would risk merge conflicts whenever they import new changes that include a - // bootstrap compiler bump. - // - // To lessen the pain, a big block of comments is placed between the configuration and the - // auto-generated parts of the file, preventing git diffs of the config to include parts of the - // auto-generated content and vice versa. This should prevent merge conflicts. - #[serde(rename = "__comments")] - comments: Vec, - compiler: Stage0Toolchain, - rustfmt: Option, - checksums_sha256: IndexMap, -} - -#[derive(Debug, serde::Serialize, serde::Deserialize)] -struct Config { - dist_server: String, - // There are other fields in the configuration, which will be read by src/bootstrap or other - // tools consuming stage0.json. To avoid the need to update bump-stage0 every time a new field - // is added, we collect all the fields in an untyped Value and serialize them back with the - // same order and structure they were deserialized in. - #[serde(flatten)] - other: serde_json::Value, -} - -#[derive(Debug, serde::Serialize, serde::Deserialize)] -struct Stage0Toolchain { - date: String, - version: String, -} - #[derive(Debug, serde::Serialize, serde::Deserialize)] struct Manifest { date: String, diff --git a/src/tools/cargo b/src/tools/cargo index 05364cb2f61a2..4de0094ac7874 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 05364cb2f61a2c2b091e061c1f42b207dfb5f81f +Subproject commit 4de0094ac78743d2c8ff682489e35c8a7cafe8e4 diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs index 3f87ed8df2bf3..b4290b6437f27 100644 --- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs +++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help; use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{self, FieldDef, GenericArg, List}; +use rustc_middle::ty::{self, FieldDef}; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -85,7 +85,7 @@ fn is_union_with_two_non_zst_fields<'tcx>(cx: &LateContext<'tcx>, item: &Item<'t } } -fn is_zst<'tcx>(cx: &LateContext<'tcx>, field: &FieldDef, args: &'tcx List>) -> bool { +fn is_zst<'tcx>(cx: &LateContext<'tcx>, field: &FieldDef, args: ty::GenericArgsRef<'tcx>) -> bool { let ty = field.ty(cx.tcx, args); if let Ok(layout) = cx.layout_of(ty) { layout.is_zst() diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index b936b28470b53..c6aef9ac2d606 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -382,7 +382,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> { cx, impl_ty, trait_id, - &args[..cx.tcx.generics_of(trait_id).params.len() - 1], + &args[..cx.tcx.generics_of(trait_id).own_params.len() - 1], ) { false diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 42cd19fb8eca5..9662c8f4fe2fc 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -480,7 +480,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> // Vec<(param_def, needs_eq)> let mut params = tcx .generics_of(did) - .params + .own_params .iter() .map(|p| (p, matches!(p.kind, GenericParamDefKind::Type { .. }))) .collect::>(); diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 386d4c3c317f6..6715de52649d4 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_hir; use rustc_hir::{intravisit, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; -use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::layout::LayoutOf; @@ -105,8 +104,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { too_large_for_stack: self.too_large_for_stack, }; - let infcx = cx.tcx.infer_ctxt().build(); - ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body); + ExprUseVisitor::for_clippy(cx, fn_def_id, &mut v).consume_body(body).into_ok(); for node in v.set { span_lint_hir( diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 18f4e51ebd663..2c2daac023492 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -5,6 +5,7 @@ use rustc_hir::{Body, FnDecl}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind}; +use rustc_middle::ty::print::PrintTraitRefExt; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs index 3bf8d61895585..dc935ed3d7fe7 100644 --- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs +++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs @@ -148,7 +148,7 @@ fn try_resolve_type<'tcx>( match args.get(index - 1) { Some(GenericArg::Type(ty)) => Some(lower_ty(tcx, ty)), Some(_) => None, - None => Some(tcx.type_of(generics.params[index].def_id).skip_binder()), + None => Some(tcx.type_of(generics.own_params[index].def_id).skip_binder()), } } diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs index c749a71233033..a75dfaf286fdf 100644 --- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs +++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs @@ -225,7 +225,7 @@ impl {self_ty_without_ref} {{ && let ImplItemKind::Fn(sig, _) = item.kind && let FnRetTy::Return(ret) = sig.decl.output && is_nameable_in_impl_trait(ret) - && cx.tcx.generics_of(item_did).params.is_empty() + && cx.tcx.generics_of(item_did).own_params.is_empty() && sig.decl.implicit_self == expected_implicit_self && sig.decl.inputs.len() == 1 && let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id()) diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 2c44c3881aa77..a8bfbbdd9ecab 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -8,6 +8,7 @@ #![feature(never_type)] #![feature(rustc_private)] #![feature(stmt_expr_attributes)] +#![feature(unwrap_infallible)] #![recursion_limit = "512"] #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![allow( diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index 5047092192f42..6b9ecf5f14130 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -4,7 +4,6 @@ use clippy_utils::{get_enclosing_block, higher, path_to_local}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Node, PatKind}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; -use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty; @@ -61,15 +60,12 @@ fn check_for_mutation( span_low: None, span_high: None, }; - let infcx = cx.tcx.infer_ctxt().build(); - ExprUseVisitor::new( - &mut delegate, - &infcx, + ExprUseVisitor::for_clippy( + cx, body.hir_id.owner.def_id, - cx.param_env, - cx.typeck_results(), + &mut delegate, ) - .walk_expr(body); + .walk_expr(body).into_ok(); delegate.mutation_span() } diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs index d76b94eba23ed..83c16d4466d06 100644 --- a/src/tools/clippy/clippy_lints/src/manual_assert.rs +++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs @@ -1,10 +1,9 @@ -use crate::rustc_lint::LintContext; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::{is_panic, root_macro_call}; use clippy_utils::{is_else_clause, is_parent_stmt, peel_blocks_with_stmt, span_extract_comment, sugg}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, UnOp}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 10c3203725a81..f775ea072e1f0 100644 --- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -6,7 +6,7 @@ use rustc_errors::{Applicability, Diag}; use rustc_hir::intravisit::{walk_expr, Visitor}; use rustc_hir::{Arm, Expr, ExprKind, MatchSource}; use rustc_lint::{LateContext, LintContext}; -use rustc_middle::ty::{GenericArgKind, Ty, TypeAndMut}; +use rustc_middle::ty::{GenericArgKind, Ty}; use rustc_span::Span; use super::SIGNIFICANT_DROP_IN_SCRUTINEE; @@ -234,9 +234,9 @@ impl<'a, 'tcx> SigDropHelper<'a, 'tcx> { } let ty = self.sig_drop_checker.get_type(expr); if ty.is_ref() { - // We checked that the type was ref, so builtin_deref will return Some TypeAndMut, - // but let's avoid any chance of an ICE - if let Some(TypeAndMut { ty, .. }) = ty.builtin_deref(true) { + // We checked that the type was ref, so builtin_deref will return Some, + // but let's avoid any chance of an ICE. + if let Some(ty) = ty.builtin_deref(true) { if ty.is_trivially_pure_clone_copy() { self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveAndDerefToCopy); } else if allow_move_and_clone { diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs index 03b4680c52242..a52d38790a2bd 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs @@ -12,7 +12,6 @@ use rustc_span::sym; use super::ITER_OVEREAGER_CLONED; use crate::redundant_clone::REDUNDANT_CLONE; -use crate::rustc_trait_selection::infer::TyCtxtInferExt; #[derive(Clone, Copy)] pub(super) enum Op<'a> { @@ -69,16 +68,13 @@ pub(super) fn check<'tcx>( let mut delegate = MoveDelegate { used_move: HirIdSet::default(), }; - let infcx = cx.tcx.infer_ctxt().build(); - ExprUseVisitor::new( + ExprUseVisitor::for_clippy( + cx, + closure.def_id, &mut delegate, - &infcx, - closure.body.hir_id.owner.def_id, - cx.param_env, - cx.typeck_results(), ) - .consume_body(body); + .consume_body(body).into_ok(); let mut to_be_discarded = false; diff --git a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs index 0842a87282475..934b9f490addf 100644 --- a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs +++ b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs @@ -76,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch { }; // get the names of the generic parameters in the type - let type_params = &cx.tcx.generics_of(defid).params; + let type_params = &cx.tcx.generics_of(defid).own_params; let type_param_names: Vec<_> = type_params .iter() .filter_map(|p| match p.kind { diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index a24cd4f9c8a35..e6c6a15b8d48a 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -13,7 +13,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::{Rvalue, StatementKind}; use rustc_middle::ty::{ - self, ClauseKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, List, ParamTy, ProjectionPredicate, Ty, + self, ClauseKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, ParamTy, ProjectionPredicate, Ty, }; use rustc_session::impl_lint_pass; use rustc_span::symbol::sym; @@ -161,7 +161,7 @@ fn needless_borrow_count<'tcx>( cx: &LateContext<'tcx>, possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>, fn_id: DefId, - callee_args: &'tcx List>, + callee_args: ty::GenericArgsRef<'tcx>, arg_index: usize, param_ty: ParamTy, mut expr: &Expr<'tcx>, diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index 9e47c3ad0b7fb..9b852f52ea1eb 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -11,7 +11,6 @@ use rustc_hir::{ PatKind, }; use rustc_hir_typeck::expr_use_visitor as euv; -use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TyCtxt, UpvarId, UpvarPath}; @@ -102,7 +101,6 @@ fn should_skip<'tcx>( fn check_closures<'tcx>( ctx: &mut MutablyUsedVariablesCtxt<'tcx>, cx: &LateContext<'tcx>, - infcx: &InferCtxt<'tcx>, checked_closures: &mut FxHashSet, closures: FxHashSet, ) { @@ -119,7 +117,7 @@ fn check_closures<'tcx>( .associated_body() .map(|(_, body_id)| hir.body(body_id)) { - euv::ExprUseVisitor::new(ctx, infcx, closure, cx.param_env, cx.typeck_results()).consume_body(body); + euv::ExprUseVisitor::for_clippy(cx, closure, &mut *ctx).consume_body(body).into_ok(); } } } @@ -196,8 +194,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { async_closures: FxHashSet::default(), tcx: cx.tcx, }; - let infcx = cx.tcx.infer_ctxt().build(); - euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body); + euv::ExprUseVisitor::for_clippy(cx, fn_def_id, &mut ctx).consume_body(body).into_ok(); let mut checked_closures = FxHashSet::default(); @@ -210,13 +207,13 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { } ControlFlow::<()>::Continue(()) }); - check_closures(&mut ctx, cx, &infcx, &mut checked_closures, closures); + check_closures(&mut ctx, cx, &mut checked_closures, closures); if is_async { while !ctx.async_closures.is_empty() { let async_closures = ctx.async_closures.clone(); ctx.async_closures.clear(); - check_closures(&mut ctx, cx, &infcx, &mut checked_closures, async_closures); + check_closures(&mut ctx, cx, &mut checked_closures, async_closures); } } ctx.generate_mutably_used_ids_from_aliases() diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 39d374d0d27fd..0986571d0f281 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -13,7 +13,6 @@ use rustc_hir::{ TyKind, }; use rustc_hir_typeck::expr_use_visitor as euv; -use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; @@ -134,8 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { // function body. let MovedVariablesCtxt { moved_vars } = { let mut ctx = MovedVariablesCtxt::default(); - let infcx = cx.tcx.infer_ctxt().build(); - euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body); + euv::ExprUseVisitor::for_clippy(cx, fn_def_id, &mut ctx).consume_body(body).into_ok(); ctx }; diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs index 435eb9048f587..910e584a7a0f9 100644 --- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs @@ -11,7 +11,6 @@ use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, Pl use rustc_lint::LateContext; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::BorrowKind; -use rustc_trait_selection::infer::TyCtxtInferExt; use super::ASSIGN_OP_PATTERN; @@ -119,15 +118,8 @@ fn imm_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> HirIdSet { } let mut s = S(HirIdSet::default()); - let infcx = cx.tcx.infer_ctxt().build(); - let mut v = ExprUseVisitor::new( - &mut s, - &infcx, - cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()), - cx.param_env, - cx.typeck_results(), - ); - v.consume_expr(e); + let v = ExprUseVisitor::for_clippy(cx, e.hir_id.owner.def_id, &mut s); + v.consume_expr(e).into_ok(); s.0 } @@ -151,14 +143,7 @@ fn mut_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> HirIdSet { } let mut s = S(HirIdSet::default()); - let infcx = cx.tcx.infer_ctxt().build(); - let mut v = ExprUseVisitor::new( - &mut s, - &infcx, - cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()), - cx.param_env, - cx.typeck_results(), - ); - v.consume_expr(e); + let v = ExprUseVisitor::for_clippy(cx, e.hir_id.owner.def_id, &mut s); + v.consume_expr(e).into_ok(); s.0 } diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs index ea8ed28ba62ba..208b20a7a0691 100644 --- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs +++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs @@ -70,7 +70,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default(); let with_deref = arg_ty .builtin_deref(true) - .and_then(|tam| symmetric_partial_eq(cx, tam.ty, other_ty)) + .and_then(|ty| symmetric_partial_eq(cx, ty, other_ty)) .unwrap_or_default(); if !with_deref.is_implemented() && !without_deref.is_implemented() { diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index 2863eb190d341..47d3ed08b8ec1 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -1,4 +1,3 @@ -use crate::rustc_lint::LintContext; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir}; use clippy_utils::get_parent_expr; use clippy_utils::sugg::Sugg; @@ -9,7 +8,7 @@ use rustc_hir::intravisit::{Visitor as HirVisitor, Visitor}; use rustc_hir::{ intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, ExprKind, Node, }; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; use rustc_middle::ty; diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs index 6540626f7d5a3..63237c655ef17 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -1,9 +1,8 @@ -use crate::rustc_lint::LintContext; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use rustc_errors::Applicability; use rustc_hir::{Block, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; use rustc_span::{ExpnKind, MacroKind, Span}; diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs index 18fbbdb407911..acf44a9bb5ab4 100644 --- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs +++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs @@ -201,8 +201,8 @@ impl SingleComponentPathImports { if segments.is_empty() { // keep track of `use {some_module, some_other_module};` usages - if let UseTreeKind::Nested(trees) = &use_tree.kind { - for tree in trees { + if let UseTreeKind::Nested { items, .. } = &use_tree.kind { + for tree in items { let segments = &tree.0.prefix.segments; if segments.len() == 1 { if let UseTreeKind::Simple(None) = tree.0.kind { @@ -229,8 +229,8 @@ impl SingleComponentPathImports { } // nested case such as `use self::{module1::Struct1, module2::Struct2}` - if let UseTreeKind::Nested(trees) = &use_tree.kind { - for tree in trees { + if let UseTreeKind::Nested { items, .. } = &use_tree.kind { + for tree in items { let segments = &tree.0.prefix.segments; if !segments.is_empty() { imports_reused_with_self.push(segments[0].ident.name); diff --git a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs index c44f5150dd1a9..1dfc9f7091e8c 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs @@ -87,7 +87,7 @@ pub(super) fn check<'tcx>( && is_normalizable(cx, cx.param_env, from_ty) && is_normalizable(cx, cx.param_env, to_ty) // we only want to lint if the target type has a niche that is larger than the one of the source type - // e.g. `u8` to `NonZeroU8` should lint, but `NonZeroU8` to `u8` should not + // e.g. `u8` to `NonZero` should lint, but `NonZero` to `u8` should not && let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from_ty)) && let Ok(to_layout) = cx.tcx.layout_of(cx.param_env.and(to_ty)) && match (from_layout.largest_niche, to_layout.largest_niche) { diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs index 7fa536a1a29d9..598032ccdebed 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs @@ -257,7 +257,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for transmutes from integers to `NonZero*` types, and suggests their `new_unchecked` + /// Checks for transmutes from `T` to `NonZero`, and suggests the `new_unchecked` /// method instead. /// /// ### Why is this bad? @@ -266,13 +266,13 @@ declare_clippy_lint! { /// /// ### Example /// ```no_run - /// # use core::num::NonZeroU32; - /// let _non_zero: NonZeroU32 = unsafe { std::mem::transmute(123) }; + /// # use core::num::NonZero; + /// let _: NonZero = unsafe { std::mem::transmute(123) }; /// ``` /// Use instead: /// ```no_run - /// # use core::num::NonZeroU32; - /// let _non_zero = unsafe { NonZeroU32::new_unchecked(123) }; + /// # use core::num::NonZero; + /// let _: NonZero = unsafe { NonZero::new_unchecked(123) }; /// ``` #[clippy::version = "1.69.0"] pub TRANSMUTE_INT_TO_NON_ZERO, diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs index 2bea3be3d6030..7d824ef213900 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs @@ -26,45 +26,22 @@ pub(super) fn check<'tcx>( return false; }; - // FIXME: This can be simplified once `NonZero` is stable. - let coercible_types = [ - ("NonZeroU8", tcx.types.u8), - ("NonZeroU16", tcx.types.u16), - ("NonZeroU32", tcx.types.u32), - ("NonZeroU64", tcx.types.u64), - ("NonZeroU128", tcx.types.u128), - ("NonZeroUsize", tcx.types.usize), - ("NonZeroI8", tcx.types.i8), - ("NonZeroI16", tcx.types.i16), - ("NonZeroI32", tcx.types.i32), - ("NonZeroI64", tcx.types.i64), - ("NonZeroI128", tcx.types.i128), - ("NonZeroIsize", tcx.types.isize), - ]; - - let int_type = substs.type_at(0); - - let Some(nonzero_alias) = coercible_types.iter().find_map(|(nonzero_alias, t)| { - if *t == int_type && *t == from_ty { - Some(nonzero_alias) - } else { - None - } - }) else { - return false; - }; + let int_ty = substs.type_at(0); + if from_ty != int_ty { + return false; + } span_lint_and_then( cx, TRANSMUTE_INT_TO_NON_ZERO, e.span, - format!("transmute from a `{from_ty}` to a `{nonzero_alias}`"), + format!("transmute from a `{from_ty}` to a `{}<{int_ty}>`", sym::NonZero), |diag| { let arg = sugg::Sugg::hir(cx, arg, ".."); diag.span_suggestion( e.span, "consider using", - format!("{nonzero_alias}::{}({arg})", sym::new_unchecked), + format!("{}::{}({arg})", sym::NonZero, sym::new_unchecked), Applicability::Unspecified, ); }, diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs index ddee06b59cae1..528a1dfcfc10f 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs @@ -36,8 +36,8 @@ declare_lint_pass!(UnnecessarySelfImports => [UNNECESSARY_SELF_IMPORTS]); impl EarlyLintPass for UnnecessarySelfImports { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { if let ItemKind::Use(use_tree) = &item.kind - && let UseTreeKind::Nested(nodes) = &use_tree.kind - && let [(self_tree, _)] = &**nodes + && let UseTreeKind::Nested { items, .. } = &use_tree.kind + && let [(self_tree, _)] = &**items && let [self_seg] = &*self_tree.prefix.segments && self_seg.ident.name == kw::SelfLower && let Some(last_segment) = use_tree.prefix.segments.last() diff --git a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs index 51b3ea93b6dc9..309eaedac8d29 100644 --- a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs +++ b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs @@ -49,8 +49,8 @@ fn check_use_tree(use_tree: &UseTree, cx: &EarlyContext<'_>, span: Span) { unsafe_to_safe_check(old_name, new_name, cx, span); }, UseTreeKind::Simple(None) | UseTreeKind::Glob => {}, - UseTreeKind::Nested(ref nested_use_tree) => { - for (use_tree, _) in nested_use_tree { + UseTreeKind::Nested { ref items, .. } => { + for (use_tree, _) in items { check_use_tree(use_tree, cx, span); } }, diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index 2622abd59cbd6..5b2841dcd8330 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -6,7 +6,6 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor}; use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, PathSegment, UnOp}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceWithHirId}; -use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::lint::in_external_macro; @@ -252,16 +251,13 @@ impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> { local_id: unwrap_info.local_id, }; - let infcx = self.cx.tcx.infer_ctxt().build(); - let mut vis = ExprUseVisitor::new( - &mut delegate, - &infcx, + let vis = ExprUseVisitor::for_clippy( + self.cx, cond.hir_id.owner.def_id, - self.cx.param_env, - self.cx.typeck_results(), + &mut delegate, ); - vis.walk_expr(cond); - vis.walk_expr(branch); + vis.walk_expr(cond).into_ok(); + vis.walk_expr(branch).into_ok(); if delegate.is_mutated { // if the variable is mutated, we don't know whether it can be unwrapped. diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 529d20126b22c..d3bbc66bcaea0 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -648,7 +648,7 @@ pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool { match (l, r) { (Glob, Glob) => true, (Simple(l), Simple(r)) => both(l, r, |l, r| eq_id(*l, *r)), - (Nested(l), Nested(r)) => over(l, r, |(l, _), (r, _)| eq_use_tree(l, r)), + (Nested { items: l, .. }, Nested { items: r, .. }) => over(l, r, |(l, _), (r, _)| eq_use_tree(l, r)), _ => false, } } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index a49414a058b1c..99d7aba2f7a15 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -7,6 +7,7 @@ #![feature(never_type)] #![feature(rustc_private)] #![feature(assert_matches)] +#![feature(unwrap_infallible)] #![recursion_limit = "512"] #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![allow( diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 325c9bee05782..95851a2eed814 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -134,7 +134,7 @@ fn check_rvalue<'tcx>( ) => Err((span, "function pointer casts are not allowed in const fn".into())), Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), op, cast_ty) => { let pointee_ty = if let Some(deref_ty) = cast_ty.builtin_deref(true) { - deref_ty.ty + deref_ty } else { // We cannot allow this for now. return Err((span, "unsizing casts are only allowed for references right now".into())); @@ -402,7 +402,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx> tcx, ObligationCause::dummy_with_span(body.span), ConstCx::new(tcx, body).param_env, - TraitRef::from_lang_item(tcx, LangItem::Destruct, body.span, [ty]), + TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, Some(body.span)), [ty]), ); let infcx = tcx.infer_ctxt().build(); diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 8d6057272c4e7..bf03c6c16015c 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -11,7 +11,6 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{Closure, ExprKind, HirId, MutTy, TyKind}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; -use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{EarlyContext, LateContext, LintContext}; use rustc_middle::hir::place::ProjectionKind; use rustc_middle::mir::{FakeReadCause, Mutability}; @@ -831,8 +830,9 @@ pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Opti applicability: Applicability::MachineApplicable, }; - let infcx = cx.tcx.infer_ctxt().build(); - ExprUseVisitor::new(&mut visitor, &infcx, def_id, cx.param_env, cx.typeck_results()).consume_body(closure_body); + ExprUseVisitor::for_clippy(cx, def_id, &mut visitor) + .consume_body(closure_body) + .into_ok(); if !visitor.suggestion_start.is_empty() { return Some(DerefClosure { diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 23750ed4d1ba0..97bba8648c5f5 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -10,7 +10,6 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, FnDecl, LangItem, TyKind, Unsafety}; -use rustc_infer::infer::type_variable::TypeVariableOrigin; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::interpret::Scalar; @@ -19,7 +18,7 @@ use rustc_middle::traits::EvaluationResult; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, - GenericParamDefKind, IntTy, List, ParamEnv, Region, RegionKind, ToPredicate, TraitRef, Ty, TyCtxt, + GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, ToPredicate, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr, }; use rustc_span::symbol::Ident; @@ -276,11 +275,7 @@ pub fn implements_trait_with_env_from_iter<'tcx>( .into_iter() .map(|arg| { arg.into().unwrap_or_else(|| { - let orig = TypeVariableOrigin { - span: DUMMY_SP, - param_def_id: None, - }; - infcx.next_ty_var(orig).into() + infcx.next_ty_var(DUMMY_SP).into() }) }) .collect::>(); @@ -961,7 +956,11 @@ pub struct AdtVariantInfo { impl AdtVariantInfo { /// Returns ADT variants ordered by size - pub fn new<'tcx>(cx: &LateContext<'tcx>, adt: AdtDef<'tcx>, subst: &'tcx List>) -> Vec { + pub fn new<'tcx>( + cx: &LateContext<'tcx>, + adt: AdtDef<'tcx>, + subst: GenericArgsRef<'tcx> + ) -> Vec { let mut variants_size = adt .variants() .iter() @@ -1070,11 +1069,11 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 { fn assert_generic_args_match<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, args: &[GenericArg<'tcx>]) { let g = tcx.generics_of(did); let parent = g.parent.map(|did| tcx.generics_of(did)); - let count = g.parent_count + g.params.len(); + let count = g.parent_count + g.own_params.len(); let params = parent - .map_or([].as_slice(), |p| p.params.as_slice()) + .map_or([].as_slice(), |p| p.own_params.as_slice()) .iter() - .chain(&g.params) + .chain(&g.own_params) .map(|x| &x.kind); assert!( diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs index 2241494b484a8..c2ff19931d5c3 100644 --- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs @@ -176,7 +176,7 @@ fn qpath_certainty(cx: &LateContext<'_>, qpath: &QPath<'_>, resolves_to_type: bo .get(*lang_item) .map_or(Certainty::Uncertain, |def_id| { let generics = cx.tcx.generics_of(def_id); - if generics.parent_count == 0 && generics.params.is_empty() { + if generics.parent_count == 0 && generics.own_params.is_empty() { Certainty::Certain(if resolves_to_type { Some(def_id) } else { None }) } else { Certainty::Uncertain @@ -206,7 +206,7 @@ fn path_segment_certainty( // Checking `res_generics_def_id(..)` before calling `generics_of` avoids an ICE. if cx.tcx.res_generics_def_id(path_segment.res).is_some() { let generics = cx.tcx.generics_of(def_id); - let count = generics.params.len() - usize::from(generics.host_effect_index.is_some()); + let count = generics.own_params.len() - usize::from(generics.host_effect_index.is_some()); let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && count == 0 { Certainty::Certain(None) } else { @@ -299,7 +299,7 @@ fn type_is_inferable_from_arguments(cx: &LateContext<'_>, expr: &Expr<'_>) -> bo let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder(); // Check that all type parameters appear in the functions input types. - (0..(generics.parent_count + generics.params.len()) as u32).all(|index| { + (0..(generics.parent_count + generics.own_params.len()) as u32).all(|index| { Some(index as usize) == generics.host_effect_index || fn_sig .inputs() diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index a145920aa85ed..9abb4ef9b8d3a 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -5,7 +5,6 @@ use hir::def::Res; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, Expr, ExprKind, HirId, HirIdSet}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, Place, PlaceBase, PlaceWithHirId}; -use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::mir::FakeReadCause; @@ -17,15 +16,13 @@ pub fn mutated_variables<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) -> used_mutably: HirIdSet::default(), skip: false, }; - let infcx = cx.tcx.infer_ctxt().build(); - ExprUseVisitor::new( - &mut delegate, - &infcx, + ExprUseVisitor::for_clippy( + cx, expr.hir_id.owner.def_id, - cx.param_env, - cx.typeck_results(), + &mut delegate, ) - .walk_expr(expr); + .walk_expr(expr) + .into_ok(); if delegate.skip { return None; diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs index e678d40795ee8..3f712f453fa0a 100644 --- a/src/tools/clippy/lintcheck/src/config.rs +++ b/src/tools/clippy/lintcheck/src/config.rs @@ -1,5 +1,5 @@ use clap::Parser; -use std::num::NonZeroUsize; +use std::num::NonZero; use std::path::PathBuf; #[derive(Clone, Debug, Parser)] @@ -61,7 +61,7 @@ impl LintcheckConfig { config.max_jobs = if config.fix || config.recursive { 1 } else { - std::thread::available_parallelism().map_or(1, NonZeroUsize::get) + std::thread::available_parallelism().map_or(1, NonZero::get) }; }; diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs index 66d71f337f2f6..33a91e8bbbe53 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs @@ -15,7 +15,7 @@ extern crate proc_macro_derive; -use core::num::{NonZeroUsize, Saturating, Wrapping}; +use core::num::{NonZero, Saturating, Wrapping}; const ONE: i32 = 1; const ZERO: i32 = 0; @@ -494,15 +494,15 @@ pub fn issue_11262() { } pub fn issue_11392() { - fn example_div(unsigned: usize, nonzero_unsigned: NonZeroUsize) -> usize { + fn example_div(unsigned: usize, nonzero_unsigned: NonZero) -> usize { unsigned / nonzero_unsigned } - fn example_rem(unsigned: usize, nonzero_unsigned: NonZeroUsize) -> usize { + fn example_rem(unsigned: usize, nonzero_unsigned: NonZero) -> usize { unsigned % nonzero_unsigned } - let (unsigned, nonzero_unsigned) = (0, NonZeroUsize::new(1).unwrap()); + let (unsigned, nonzero_unsigned) = (0, NonZero::new(1).unwrap()); example_div(unsigned, nonzero_unsigned); example_rem(unsigned, nonzero_unsigned); } diff --git a/src/tools/clippy/tests/ui/eager_transmute.fixed b/src/tools/clippy/tests/ui/eager_transmute.fixed index c29e7dd9ab3ea..ba4342462dca0 100644 --- a/src/tools/clippy/tests/ui/eager_transmute.fixed +++ b/src/tools/clippy/tests/ui/eager_transmute.fixed @@ -2,7 +2,7 @@ #![warn(clippy::eager_transmute)] #![allow(clippy::transmute_int_to_non_zero, clippy::missing_transmute_annotations)] -use std::num::NonZeroU8; +use std::num::NonZero; #[repr(u8)] enum Opcode { @@ -85,21 +85,21 @@ macro_rules! impls { } impls!(NonMaxU8, NonZeroNonMaxU8); -fn niche_tests(v1: u8, v2: NonZeroU8, v3: NonZeroNonMaxU8) { - // u8 -> NonZeroU8, do lint - let _: Option = (v1 > 0).then(|| unsafe { std::mem::transmute(v1) }); +fn niche_tests(v1: u8, v2: NonZero, v3: NonZeroNonMaxU8) { + // u8 -> NonZero, do lint + let _: Option> = (v1 > 0).then(|| unsafe { std::mem::transmute(v1) }); - // NonZeroU8 -> u8, don't lint, target type has no niche and therefore a higher validity range - let _: Option = (v2 > NonZeroU8::new(1).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); + // NonZero -> u8, don't lint, target type has no niche and therefore a higher validity range + let _: Option = (v2 > NonZero::new(1u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); - // NonZeroU8 -> NonMaxU8, do lint, different niche - let _: Option = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) }); + // NonZero -> NonMaxU8, do lint, different niche + let _: Option = (v2 < NonZero::new(255u8).unwrap()).then(|| unsafe { std::mem::transmute(v2) }); // NonZeroNonMaxU8 -> NonMaxU8, don't lint, target type has more validity let _: Option = (v3 < 255).then_some(unsafe { std::mem::transmute(v2) }); - // NonZeroU8 -> NonZeroNonMaxU8, do lint, target type has less validity - let _: Option = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) }); + // NonZero -> NonZeroNonMaxU8, do lint, target type has less validity + let _: Option = (v2 < NonZero::new(255u8).unwrap()).then(|| unsafe { std::mem::transmute(v2) }); } fn main() {} diff --git a/src/tools/clippy/tests/ui/eager_transmute.rs b/src/tools/clippy/tests/ui/eager_transmute.rs index 491a9485c9327..9750e87ce5741 100644 --- a/src/tools/clippy/tests/ui/eager_transmute.rs +++ b/src/tools/clippy/tests/ui/eager_transmute.rs @@ -2,7 +2,7 @@ #![warn(clippy::eager_transmute)] #![allow(clippy::transmute_int_to_non_zero, clippy::missing_transmute_annotations)] -use std::num::NonZeroU8; +use std::num::NonZero; #[repr(u8)] enum Opcode { @@ -85,21 +85,21 @@ macro_rules! impls { } impls!(NonMaxU8, NonZeroNonMaxU8); -fn niche_tests(v1: u8, v2: NonZeroU8, v3: NonZeroNonMaxU8) { - // u8 -> NonZeroU8, do lint - let _: Option = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) }); +fn niche_tests(v1: u8, v2: NonZero, v3: NonZeroNonMaxU8) { + // u8 -> NonZero, do lint + let _: Option> = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) }); - // NonZeroU8 -> u8, don't lint, target type has no niche and therefore a higher validity range - let _: Option = (v2 > NonZeroU8::new(1).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); + // NonZero -> u8, don't lint, target type has no niche and therefore a higher validity range + let _: Option = (v2 > NonZero::new(1u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); - // NonZeroU8 -> NonMaxU8, do lint, different niche - let _: Option = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); + // NonZero -> NonMaxU8, do lint, different niche + let _: Option = (v2 < NonZero::new(255u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); // NonZeroNonMaxU8 -> NonMaxU8, don't lint, target type has more validity let _: Option = (v3 < 255).then_some(unsafe { std::mem::transmute(v2) }); - // NonZeroU8 -> NonZeroNonMaxU8, do lint, target type has less validity - let _: Option = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); + // NonZero -> NonZeroNonMaxU8, do lint, target type has less validity + let _: Option = (v2 < NonZero::new(255u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); } fn main() {} diff --git a/src/tools/clippy/tests/ui/eager_transmute.stderr b/src/tools/clippy/tests/ui/eager_transmute.stderr index b9a4321d99efe..5cf7bd49a929e 100644 --- a/src/tools/clippy/tests/ui/eager_transmute.stderr +++ b/src/tools/clippy/tests/ui/eager_transmute.stderr @@ -155,36 +155,36 @@ LL | (op < 4).then(|| std::mem::transmute::<_, Opcode>(op)); | ~~~~ ++ error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:90:60 + --> tests/ui/eager_transmute.rs:90:62 | -LL | let _: Option = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) }); - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _: Option> = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) }); + | ^^^^^^^^^^^^^^^^^^^^^^^ | help: consider using `bool::then` to only transmute if the condition holds | -LL | let _: Option = (v1 > 0).then(|| unsafe { std::mem::transmute(v1) }); - | ~~~~ ++ +LL | let _: Option> = (v1 > 0).then(|| unsafe { std::mem::transmute(v1) }); + | ~~~~ ++ error: this transmute is always evaluated eagerly, even if the condition is false --> tests/ui/eager_transmute.rs:96:86 | -LL | let _: Option = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); +LL | let _: Option = (v2 < NonZero::new(255u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); | ^^^^^^^^^^^^^^^^^^^^^^^ | help: consider using `bool::then` to only transmute if the condition holds | -LL | let _: Option = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) }); +LL | let _: Option = (v2 < NonZero::new(255u8).unwrap()).then(|| unsafe { std::mem::transmute(v2) }); | ~~~~ ++ error: this transmute is always evaluated eagerly, even if the condition is false --> tests/ui/eager_transmute.rs:102:93 | -LL | let _: Option = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); +LL | let _: Option = (v2 < NonZero::new(255u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); | ^^^^^^^^^^^^^^^^^^^^^^^ | help: consider using `bool::then` to only transmute if the condition holds | -LL | let _: Option = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) }); +LL | let _: Option = (v2 < NonZero::new(255u8).unwrap()).then(|| unsafe { std::mem::transmute(v2) }); | ~~~~ ++ error: aborting due to 17 previous errors diff --git a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.fixed b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.fixed index fe8db3dcb0cf9..1a48051ec8c4d 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.fixed +++ b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.fixed @@ -1,7 +1,7 @@ #![warn(clippy::transmute_int_to_non_zero)] #![allow(clippy::missing_transmute_annotations)] -use core::num::*; +use core::num::NonZero; fn main() { let int_u8: u8 = 1; @@ -16,38 +16,38 @@ fn main() { let int_i64: i64 = 1; let int_i128: i128 = 1; - let _: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(int_u8) }; - //~^ ERROR: transmute from a `u8` to a `NonZeroU8` + let _: NonZero = unsafe { NonZero::new_unchecked(int_u8) }; + //~^ ERROR: transmute from a `u8` to a `NonZero` //~| NOTE: `-D clippy::transmute-int-to-non-zero` implied by `-D warnings` - let _: NonZeroU16 = unsafe { NonZeroU16::new_unchecked(int_u16) }; - //~^ ERROR: transmute from a `u16` to a `NonZeroU16` - let _: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(int_u32) }; - //~^ ERROR: transmute from a `u32` to a `NonZeroU32` - let _: NonZeroU64 = unsafe { NonZeroU64::new_unchecked(int_u64) }; - //~^ ERROR: transmute from a `u64` to a `NonZeroU64` - let _: NonZeroU128 = unsafe { NonZeroU128::new_unchecked(int_u128) }; - //~^ ERROR: transmute from a `u128` to a `NonZeroU128` + let _: NonZero = unsafe { NonZero::new_unchecked(int_u16) }; + //~^ ERROR: transmute from a `u16` to a `NonZero` + let _: NonZero = unsafe { NonZero::new_unchecked(int_u32) }; + //~^ ERROR: transmute from a `u32` to a `NonZero` + let _: NonZero = unsafe { NonZero::new_unchecked(int_u64) }; + //~^ ERROR: transmute from a `u64` to a `NonZero` + let _: NonZero = unsafe { NonZero::new_unchecked(int_u128) }; + //~^ ERROR: transmute from a `u128` to a `NonZero` - let _: NonZeroI8 = unsafe { NonZeroI8::new_unchecked(int_i8) }; - //~^ ERROR: transmute from a `i8` to a `NonZeroI8` - let _: NonZeroI16 = unsafe { NonZeroI16::new_unchecked(int_i16) }; - //~^ ERROR: transmute from a `i16` to a `NonZeroI16` - let _: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(int_i32) }; - //~^ ERROR: transmute from a `i32` to a `NonZeroI32` - let _: NonZeroI64 = unsafe { NonZeroI64::new_unchecked(int_i64) }; - //~^ ERROR: transmute from a `i64` to a `NonZeroI64` - let _: NonZeroI128 = unsafe { NonZeroI128::new_unchecked(int_i128) }; - //~^ ERROR: transmute from a `i128` to a `NonZeroI128` + let _: NonZero = unsafe { NonZero::new_unchecked(int_i8) }; + //~^ ERROR: transmute from a `i8` to a `NonZero` + let _: NonZero = unsafe { NonZero::new_unchecked(int_i16) }; + //~^ ERROR: transmute from a `i16` to a `NonZero` + let _: NonZero = unsafe { NonZero::new_unchecked(int_i32) }; + //~^ ERROR: transmute from a `i32` to a `NonZero` + let _: NonZero = unsafe { NonZero::new_unchecked(int_i64) }; + //~^ ERROR: transmute from a `i64` to a `NonZero` + let _: NonZero = unsafe { NonZero::new_unchecked(int_i128) }; + //~^ ERROR: transmute from a `i128` to a `NonZero` - let _: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(int_u8) }; - let _: NonZeroU16 = unsafe { NonZeroU16::new_unchecked(int_u16) }; - let _: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(int_u32) }; - let _: NonZeroU64 = unsafe { NonZeroU64::new_unchecked(int_u64) }; - let _: NonZeroU128 = unsafe { NonZeroU128::new_unchecked(int_u128) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_u8) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_u16) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_u32) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_u64) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_u128) }; - let _: NonZeroI8 = unsafe { NonZeroI8::new_unchecked(int_i8) }; - let _: NonZeroI16 = unsafe { NonZeroI16::new_unchecked(int_i16) }; - let _: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(int_i32) }; - let _: NonZeroI64 = unsafe { NonZeroI64::new_unchecked(int_i64) }; - let _: NonZeroI128 = unsafe { NonZeroI128::new_unchecked(int_i128) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_i8) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_i16) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_i32) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_i64) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_i128) }; } diff --git a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs index a79ed5279b1f2..d8e842fb99ceb 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs +++ b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs @@ -1,7 +1,7 @@ #![warn(clippy::transmute_int_to_non_zero)] #![allow(clippy::missing_transmute_annotations)] -use core::num::*; +use core::num::NonZero; fn main() { let int_u8: u8 = 1; @@ -16,38 +16,38 @@ fn main() { let int_i64: i64 = 1; let int_i128: i128 = 1; - let _: NonZeroU8 = unsafe { std::mem::transmute(int_u8) }; - //~^ ERROR: transmute from a `u8` to a `NonZeroU8` + let _: NonZero = unsafe { std::mem::transmute(int_u8) }; + //~^ ERROR: transmute from a `u8` to a `NonZero` //~| NOTE: `-D clippy::transmute-int-to-non-zero` implied by `-D warnings` - let _: NonZeroU16 = unsafe { std::mem::transmute(int_u16) }; - //~^ ERROR: transmute from a `u16` to a `NonZeroU16` - let _: NonZeroU32 = unsafe { std::mem::transmute(int_u32) }; - //~^ ERROR: transmute from a `u32` to a `NonZeroU32` - let _: NonZeroU64 = unsafe { std::mem::transmute(int_u64) }; - //~^ ERROR: transmute from a `u64` to a `NonZeroU64` - let _: NonZeroU128 = unsafe { std::mem::transmute(int_u128) }; - //~^ ERROR: transmute from a `u128` to a `NonZeroU128` + let _: NonZero = unsafe { std::mem::transmute(int_u16) }; + //~^ ERROR: transmute from a `u16` to a `NonZero` + let _: NonZero = unsafe { std::mem::transmute(int_u32) }; + //~^ ERROR: transmute from a `u32` to a `NonZero` + let _: NonZero = unsafe { std::mem::transmute(int_u64) }; + //~^ ERROR: transmute from a `u64` to a `NonZero` + let _: NonZero = unsafe { std::mem::transmute(int_u128) }; + //~^ ERROR: transmute from a `u128` to a `NonZero` - let _: NonZeroI8 = unsafe { std::mem::transmute(int_i8) }; - //~^ ERROR: transmute from a `i8` to a `NonZeroI8` - let _: NonZeroI16 = unsafe { std::mem::transmute(int_i16) }; - //~^ ERROR: transmute from a `i16` to a `NonZeroI16` - let _: NonZeroI32 = unsafe { std::mem::transmute(int_i32) }; - //~^ ERROR: transmute from a `i32` to a `NonZeroI32` - let _: NonZeroI64 = unsafe { std::mem::transmute(int_i64) }; - //~^ ERROR: transmute from a `i64` to a `NonZeroI64` - let _: NonZeroI128 = unsafe { std::mem::transmute(int_i128) }; - //~^ ERROR: transmute from a `i128` to a `NonZeroI128` + let _: NonZero = unsafe { std::mem::transmute(int_i8) }; + //~^ ERROR: transmute from a `i8` to a `NonZero` + let _: NonZero = unsafe { std::mem::transmute(int_i16) }; + //~^ ERROR: transmute from a `i16` to a `NonZero` + let _: NonZero = unsafe { std::mem::transmute(int_i32) }; + //~^ ERROR: transmute from a `i32` to a `NonZero` + let _: NonZero = unsafe { std::mem::transmute(int_i64) }; + //~^ ERROR: transmute from a `i64` to a `NonZero` + let _: NonZero = unsafe { std::mem::transmute(int_i128) }; + //~^ ERROR: transmute from a `i128` to a `NonZero` - let _: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(int_u8) }; - let _: NonZeroU16 = unsafe { NonZeroU16::new_unchecked(int_u16) }; - let _: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(int_u32) }; - let _: NonZeroU64 = unsafe { NonZeroU64::new_unchecked(int_u64) }; - let _: NonZeroU128 = unsafe { NonZeroU128::new_unchecked(int_u128) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_u8) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_u16) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_u32) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_u64) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_u128) }; - let _: NonZeroI8 = unsafe { NonZeroI8::new_unchecked(int_i8) }; - let _: NonZeroI16 = unsafe { NonZeroI16::new_unchecked(int_i16) }; - let _: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(int_i32) }; - let _: NonZeroI64 = unsafe { NonZeroI64::new_unchecked(int_i64) }; - let _: NonZeroI128 = unsafe { NonZeroI128::new_unchecked(int_i128) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_i8) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_i16) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_i32) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_i64) }; + let _: NonZero = unsafe { NonZero::new_unchecked(int_i128) }; } diff --git a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr index bb0b0d0ff4f06..199b8ec59d092 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr +++ b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr @@ -1,65 +1,65 @@ -error: transmute from a `u8` to a `NonZeroU8` - --> tests/ui/transmute_int_to_non_zero.rs:19:33 +error: transmute from a `u8` to a `NonZero` + --> tests/ui/transmute_int_to_non_zero.rs:19:35 | -LL | let _: NonZeroU8 = unsafe { std::mem::transmute(int_u8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU8::new_unchecked(int_u8)` +LL | let _: NonZero = unsafe { std::mem::transmute(int_u8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_u8)` | = note: `-D clippy::transmute-int-to-non-zero` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_non_zero)]` -error: transmute from a `u16` to a `NonZeroU16` - --> tests/ui/transmute_int_to_non_zero.rs:22:34 +error: transmute from a `u16` to a `NonZero` + --> tests/ui/transmute_int_to_non_zero.rs:22:36 | -LL | let _: NonZeroU16 = unsafe { std::mem::transmute(int_u16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU16::new_unchecked(int_u16)` +LL | let _: NonZero = unsafe { std::mem::transmute(int_u16) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_u16)` -error: transmute from a `u32` to a `NonZeroU32` - --> tests/ui/transmute_int_to_non_zero.rs:24:34 +error: transmute from a `u32` to a `NonZero` + --> tests/ui/transmute_int_to_non_zero.rs:24:36 | -LL | let _: NonZeroU32 = unsafe { std::mem::transmute(int_u32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU32::new_unchecked(int_u32)` +LL | let _: NonZero = unsafe { std::mem::transmute(int_u32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_u32)` -error: transmute from a `u64` to a `NonZeroU64` - --> tests/ui/transmute_int_to_non_zero.rs:26:34 +error: transmute from a `u64` to a `NonZero` + --> tests/ui/transmute_int_to_non_zero.rs:26:36 | -LL | let _: NonZeroU64 = unsafe { std::mem::transmute(int_u64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU64::new_unchecked(int_u64)` +LL | let _: NonZero = unsafe { std::mem::transmute(int_u64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_u64)` -error: transmute from a `u128` to a `NonZeroU128` - --> tests/ui/transmute_int_to_non_zero.rs:28:35 +error: transmute from a `u128` to a `NonZero` + --> tests/ui/transmute_int_to_non_zero.rs:28:37 | -LL | let _: NonZeroU128 = unsafe { std::mem::transmute(int_u128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU128::new_unchecked(int_u128)` +LL | let _: NonZero = unsafe { std::mem::transmute(int_u128) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_u128)` -error: transmute from a `i8` to a `NonZeroI8` - --> tests/ui/transmute_int_to_non_zero.rs:31:33 +error: transmute from a `i8` to a `NonZero` + --> tests/ui/transmute_int_to_non_zero.rs:31:35 | -LL | let _: NonZeroI8 = unsafe { std::mem::transmute(int_i8) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI8::new_unchecked(int_i8)` +LL | let _: NonZero = unsafe { std::mem::transmute(int_i8) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_i8)` -error: transmute from a `i16` to a `NonZeroI16` - --> tests/ui/transmute_int_to_non_zero.rs:33:34 +error: transmute from a `i16` to a `NonZero` + --> tests/ui/transmute_int_to_non_zero.rs:33:36 | -LL | let _: NonZeroI16 = unsafe { std::mem::transmute(int_i16) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI16::new_unchecked(int_i16)` +LL | let _: NonZero = unsafe { std::mem::transmute(int_i16) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_i16)` -error: transmute from a `i32` to a `NonZeroI32` - --> tests/ui/transmute_int_to_non_zero.rs:35:34 +error: transmute from a `i32` to a `NonZero` + --> tests/ui/transmute_int_to_non_zero.rs:35:36 | -LL | let _: NonZeroI32 = unsafe { std::mem::transmute(int_i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI32::new_unchecked(int_i32)` +LL | let _: NonZero = unsafe { std::mem::transmute(int_i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_i32)` -error: transmute from a `i64` to a `NonZeroI64` - --> tests/ui/transmute_int_to_non_zero.rs:37:34 +error: transmute from a `i64` to a `NonZero` + --> tests/ui/transmute_int_to_non_zero.rs:37:36 | -LL | let _: NonZeroI64 = unsafe { std::mem::transmute(int_i64) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI64::new_unchecked(int_i64)` +LL | let _: NonZero = unsafe { std::mem::transmute(int_i64) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_i64)` -error: transmute from a `i128` to a `NonZeroI128` - --> tests/ui/transmute_int_to_non_zero.rs:39:35 +error: transmute from a `i128` to a `NonZero` + --> tests/ui/transmute_int_to_non_zero.rs:39:37 | -LL | let _: NonZeroI128 = unsafe { std::mem::transmute(int_i128) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI128::new_unchecked(int_i128)` +LL | let _: NonZero = unsafe { std::mem::transmute(int_i128) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_i128)` error: aborting due to 10 previous errors diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 42159b147d582..c7c807d3e6846 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -932,6 +932,8 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "test-mir-pass", "unset-exec-env", "unset-rustc-env", + // Used by the tidy check `unknown_revision`. + "unused-revision-names", // tidy-alphabetical-end ]; diff --git a/src/tools/html-checker/main.rs b/src/tools/html-checker/main.rs index 9b4d2c5259806..e74f72608efc8 100644 --- a/src/tools/html-checker/main.rs +++ b/src/tools/html-checker/main.rs @@ -29,6 +29,8 @@ fn check_html_file(file: &Path) -> usize { .arg("-quiet") .arg("--mute-id") // this option is useful in case we want to mute more warnings .arg("yes") + .arg("--new-blocklevel-tags") + .arg("rustdoc-search") // custom elements .arg("--mute") .arg(&to_mute_s) .arg(file); diff --git a/src/tools/miri/.gitignore b/src/tools/miri/.gitignore index 924a93e807fe3..97e006e8b1b82 100644 --- a/src/tools/miri/.gitignore +++ b/src/tools/miri/.gitignore @@ -9,5 +9,5 @@ tex/*/out perf.data perf.data.old flamegraph.svg -tests/extern-so/libtestlib.so +tests/native-lib/libtestlib.so .auto-* diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index 60bc1d5282dd6..092ad46a7cad3 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -72,14 +72,14 @@ For example: You can (cross-)run the entire test suite using: -``` +```sh ./miri test -MIRI_TEST_TARGET=i686-unknown-linux-gnu ./miri test +./miri test --target i686-unknown-linux-gnu ``` `./miri test FILTER` only runs those tests that contain `FILTER` in their filename (including the -base directory, e.g. `./miri test fail` will run all compile-fail tests). These filters are passed -to `cargo test`, so for multiple filters you need to use `./miri test -- FILTER1 FILTER2`. +base directory, e.g. `./miri test fail` will run all compile-fail tests). Multiple filters are +supported: `./miri test FILTER1 FILTER2` runs all tests that contain either string. #### Fine grained logging @@ -139,9 +139,8 @@ and then you can use it as if it was installed by `rustup` as a component of the in the `miri` toolchain's sysroot to prevent conflicts with other toolchains. The Miri binaries in the `cargo` bin directory (usually `~/.cargo/bin`) are managed by rustup. -There's a test for the cargo wrapper in the `test-cargo-miri` directory; run -`./run-test.py` in there to execute it. Like `./miri test`, this respects the -`MIRI_TEST_TARGET` environment variable to execute the test for another target. +There's a test for the cargo wrapper in the `test-cargo-miri` directory; run `./run-test.py` in +there to execute it. You can pass `--target` to execute the test for another target. ### Using a modified standard library @@ -287,3 +286,41 @@ https. Add the following to your `.gitconfig`: [url "git@github.com:"] pushInsteadOf = https://github.com/ ``` + +## Internal environment variables + +The following environment variables are *internal* and must not be used by +anyone but Miri itself. They are used to communicate between different Miri +binaries, and as such worth documenting: + +* `CARGO_EXTRA_FLAGS` is understood by `./miri` and passed to all host cargo invocations. +* `MIRI_BE_RUSTC` can be set to `host` or `target`. It tells the Miri driver to + actually not interpret the code but compile it like rustc would. With `target`, Miri sets + some compiler flags to prepare the code for interpretation; with `host`, this is not done. + This environment variable is useful to be sure that the compiled `rlib`s are compatible + with Miri. +* `MIRI_CALLED_FROM_SETUP` is set during the Miri sysroot build, + which will re-invoke `cargo-miri` as the `rustc` to use for this build. +* `MIRI_CALLED_FROM_RUSTDOC` when set to any value tells `cargo-miri` that it is + running as a child process of `rustdoc`, which invokes it twice for each doc-test + and requires special treatment, most notably a check-only build before interpretation. + This is set by `cargo-miri` itself when running as a `rustdoc`-wrapper. +* `MIRI_CWD` when set to any value tells the Miri driver to change to the given + directory after loading all the source files, but before commencing + interpretation. This is useful if the interpreted program wants a different + working directory at run-time than at build-time. +* `MIRI_LOCAL_CRATES` is set by `cargo-miri` to tell the Miri driver which + crates should be given special treatment in diagnostics, in addition to the + crate currently being compiled. +* `MIRI_ORIG_RUSTDOC` is set and read by different phases of `cargo-miri` to remember the + value of `RUSTDOC` from before it was overwritten. +* `MIRI_REPLACE_LIBRS_IF_NOT_TEST` when set to any value enables a hack that helps bootstrap + run the standard library tests in Miri. +* `MIRI_TEST_TARGET` is set by `./miri test` (and `./x.py test miri`) to tell the test harness about + the chosen target. +* `MIRI_VERBOSE` when set to any value tells the various `cargo-miri` phases to + perform verbose logging. +* `MIRI_HOST_SYSROOT` is set by bootstrap to tell `cargo-miri` which sysroot to use for *host* + operations. +* `RUSTC_BLESS` is set by `./miri test` (and `./x.py test miri`) to indicate bless-mode to the test + harness. diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 5b3e2a588b4fa..208a8b9ee617d 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -1,39 +1,34 @@ # Miri -An experimental interpreter for [Rust][rust]'s -[mid-level intermediate representation][mir] (MIR). It can run binaries and -test suites of cargo projects and detect certain classes of -[undefined behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html), -for example: +Miri is an [Undefined Behavior][reference-ub] detection tool for Rust. It can run binaries and test +suites of cargo projects and detect unsafe code that fails to uphold its safety requirements. For +instance: * Out-of-bounds memory accesses and use-after-free * Invalid use of uninitialized data * Violation of intrinsic preconditions (an [`unreachable_unchecked`] being reached, calling [`copy_nonoverlapping`] with overlapping ranges, ...) * Not sufficiently aligned memory accesses and references -* Violation of *some* basic type invariants (a `bool` that is not 0 or 1, for example, +* Violation of basic type invariants (a `bool` that is not 0 or 1, for example, or an invalid enum discriminant) * **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing for reference types * **Experimental**: Violations of the [Tree Borrows] aliasing rules, as an optional alternative to [Stacked Borrows] -* **Experimental**: Data races +* **Experimental**: Data races and emulation of weak memory effects, i.e., + atomic reads can return outdated values. On top of that, Miri will also tell you about memory leaks: when there is memory still allocated at the end of the execution, and that memory is not reachable from a global `static`, Miri will raise an error. -Miri supports almost all Rust language features; in particular, unwinding and -concurrency are properly supported (including some experimental emulation of -weak memory effects, i.e., reads can return outdated values). - You can use Miri to emulate programs on other targets, e.g. to ensure that byte-level data manipulation works correctly both on little-endian and big-endian systems. See [cross-interpretation](#cross-interpretation-running-for-different-targets) below. -Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you +Miri has already discovered many [real-world bugs](#bugs-found-by-miri). If you found a bug with Miri, we'd appreciate if you tell us and we'll add it to the list! @@ -45,24 +40,27 @@ clocks, are replaced by deterministic "fake" implementations. Set (In particular, the "fake" system RNG APIs make Miri **not suited for cryptographic use**! Do not generate keys using Miri.) -All that said, be aware that Miri will **not catch all cases of undefined -behavior** in your program, and cannot run all programs: +All that said, be aware that Miri does **not catch every violation of the Rust specification** in +your program, not least because there is no such specification. Miri uses its own approximation of +what is and is not Undefined Behavior in Rust. To the best of our knowledge, all Undefined Behavior +that has the potential to affect a program's correctness *is* being detected by Miri (modulo +[bugs][I-misses-ub]), but you should consult [the Reference][reference-ub] for the official +definition of Undefined Behavior. Miri will be updated with the Rust compiler to protect against UB +as it is understood by the current compiler, but it makes no promises about future versions of +rustc. -* There are still plenty of open questions around the basic invariants for some - types and when these invariants even have to hold. Miri tries to avoid false - positives here, so if your program runs fine in Miri right now that is by no - means a guarantee that it is UB-free when these questions get answered. +Further caveats that Miri users should be aware of: - In particular, Miri does not check that references point to valid data. * If the program relies on unspecified details of how data is laid out, it will still run fine in Miri -- but might break (including causing UB) on different - compiler versions or different platforms. + compiler versions or different platforms. (You can use `-Zrandomize-layout` + to detect some of these cases.) * Program execution is non-deterministic when it depends, for example, on where exactly in memory allocations end up, or on the exact interleaving of concurrent threads. Miri tests one of many possible executions of your - program. You can alleviate this to some extent by running Miri with different - values for `-Zmiri-seed`, but that will still by far not explore all possible - executions. + program, but it will miss bugs that only occur in a different possible execution. + You can alleviate this to some extent by running Miri with different + values for `-Zmiri-seed`, but that will still by far not explore all possible executions. * Miri runs the program as a platform-independent interpreter, so the program has no access to most platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout, accessing environment variables, and @@ -70,8 +68,8 @@ behavior** in your program, and cannot run all programs: not support networking. System API support varies between targets; if you run on Windows it is a good idea to use `--target x86_64-unknown-linux-gnu` to get better support. -* Weak memory emulation may [produce weak behaviours](https://github.com/rust-lang/miri/issues/2301) - unobservable by compiled programs running on real hardware when `SeqCst` fences are used, and it +* Weak memory emulation may [produce weak behaviors](https://github.com/rust-lang/miri/issues/2301) + when `SeqCst` fences are used that are not actually permitted by the Rust memory model, and it cannot produce all behaviors possibly observable on real hardware. Moreover, Miri fundamentally cannot tell you whether your code is *sound*. [Soundness] is the property @@ -87,6 +85,8 @@ coverage. [Stacked Borrows]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md [Tree Borrows]: https://perso.crans.org/vanille/treebor/ [Soundness]: https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library +[reference-ub]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html +[I-misses-ub]: https://github.com/rust-lang/miri/labels/I-misses-UB ## Using Miri @@ -97,14 +97,8 @@ Install Miri on Rust nightly via `rustup`: rustup +nightly component add miri ``` -If `rustup` says the `miri` component is unavailable, that's because not all -nightly releases come with all tools. Check out -[this website](https://rust-lang.github.io/rustup-components-history) to -determine a nightly version that comes with Miri and install that using `rustup -toolchain install nightly-YYYY-MM-DD`. Either way, all of the following commands -assume the right toolchain is pinned via `rustup override set nightly` or -`rustup override set nightly-YYYY-MM-DD`. (Alternatively, use `cargo -+nightly`/`cargo +nightly-YYYY-MM-DD` for each of the following commands.) +All the following commands assume the nightly toolchain is pinned via `rustup override set nightly`. +Alternatively, use `cargo +nightly` for each of the following commands. Now you can run your project in Miri: @@ -118,12 +112,12 @@ dependencies. It will ask you for confirmation before installing anything. example, `cargo miri test filter` only runs the tests containing `filter` in their name. -You can pass arguments to Miri via `MIRIFLAGS`. For example, +You can pass [flags][miri-flags] to Miri via `MIRIFLAGS`. For example, `MIRIFLAGS="-Zmiri-disable-stacked-borrows" cargo miri run` runs the program without checking the aliasing of references. When compiling code via `cargo miri`, the `cfg(miri)` config flag is set for code -that will be interpret under Miri. You can use this to ignore test cases that fail +that will be interpreted under Miri. You can use this to ignore test cases that fail under Miri because they do things Miri does not support: ```rust @@ -159,10 +153,8 @@ endian-sensitive code. ### Running Miri on CI -To run Miri on CI, make sure that you handle the case where the latest nightly -does not ship the Miri component because it currently does not build. `rustup -toolchain install --component` knows how to handle this situation, so the -following snippet should always work: +When running Miri on CI, use the following snippet to install a nightly toolchain with the Miri +component: ```sh rustup toolchain install nightly --component miri @@ -227,7 +219,7 @@ degree documented below): - We have unofficial support (not maintained by the Miri team itself) for some further operating systems. - `freebsd`: **maintainer wanted**. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`. - `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works. - - `illumos`: maintained by @devnexen. Support very incomplete, but a basic "hello world" works. + - `solaris` / `illumos`: maintained by @devnexen. Support very incomplete, but a basic "hello world" works. - `wasm`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works. - For targets on other operating systems, Miri might fail before even reaching the `main` function. @@ -273,25 +265,12 @@ To get a backtrace, you need to disable isolation RUST_BACKTRACE=1 MIRIFLAGS="-Zmiri-disable-isolation" cargo miri test ``` -#### "found possibly newer version of crate `std` which `` depends on" - -Your build directory may contain artifacts from an earlier build that have/have -not been built for Miri. Run `cargo clean` before switching from non-Miri to -Miri builds and vice-versa. - #### "found crate `std` compiled by an incompatible version of rustc" You may be running `cargo miri` with a different compiler version than the one used to build the custom libstd that Miri uses, and Miri failed to detect that. Try running `cargo miri clean`. -#### "no mir for `std::rt::lang_start_internal`" - -This means the sysroot you are using was not compiled with Miri in mind. This -should never happen when you use `cargo miri` because that takes care of setting -up the sysroot. If you are using `miri` (the Miri driver) directly, see the -[contributors' guide](CONTRIBUTING.md) for how to use `./miri` to best do that. - ## Miri `-Z` flags and environment variables [miri-flags]: #miri--z-flags-and-environment-variables @@ -395,17 +374,17 @@ to Miri failing to detect cases of undefined behavior in a program. this flag is **unsound**. * `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak memory effects. -* `-Zmiri-extern-so-file=` is an experimental flag for providing support - for FFI calls. Functions not provided by that file are still executed via the usual Miri shims. - **WARNING**: If an invalid/incorrect `.so` file is specified, this can cause undefined behaviour in Miri itself! - And of course, Miri cannot do any checks on the actions taken by the external code. +* `-Zmiri-native-lib=` is an experimental flag for providing support + for calling native functions from inside the interpreter via FFI. Functions not provided by that + file are still executed via the usual Miri shims. + **WARNING**: If an invalid/incorrect `.so` file is specified, this can cause Undefined Behavior in Miri itself! + And of course, Miri cannot do any checks on the actions taken by the native code. Note that Miri has its own handling of file descriptors, so if you want to replace *some* functions working on file descriptors, you will have to replace *all* of them, or the two kinds of file descriptors will be mixed up. This is **work in progress**; currently, only integer arguments and return values are supported (and no, pointer/integer casts to work around this limitation will not work; - they will fail horribly). It also only works on unix hosts for now. - Follow [the discussion on supporting other types](https://github.com/rust-lang/miri/issues/2365). + they will fail horribly). It also only works on Linux hosts for now. * `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file inside a directory called ``, and can be processed @@ -484,50 +463,14 @@ by all intended entry points, i.e. `cargo miri` and `./miri {test,run}`): * `MIRI_SYSROOT` indicates the sysroot to use. When using `cargo miri`, this skips the automatic setup -- only set this if you do not want to use the automatically created sysroot. When invoking `cargo miri setup`, this indicates where the sysroot will be put. -* `MIRI_TEST_TARGET` (recognized by `./miri {test,run}`) indicates which target - architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same - purpose. * `MIRI_TEST_THREADS` (recognized by `./miri test`): set the number of threads to use for running tests. By default, the number of cores is used. * `MIRI_NO_STD` makes sure that the target's sysroot is built without libstd. This allows testing and running no_std programs. (Miri has a heuristic to detect no-std targets based on the target name; this environment variable is only needed when that heuristic fails.) -* `RUSTC_BLESS` (recognized by `./miri test` and `cargo-miri-test/run-test.py`): overwrite all - `stderr` and `stdout` files instead of checking whether the output matches. * `MIRI_SKIP_UI_CHECKS` (recognized by `./miri test`): don't check whether the `stderr` or `stdout` files match the actual output. -The following environment variables are *internal* and must not be used by -anyone but Miri itself. They are used to communicate between different Miri -binaries, and as such worth documenting: - -* `MIRI_BE_RUSTC` can be set to `host` or `target`. It tells the Miri driver to - actually not interpret the code but compile it like rustc would. With `target`, Miri sets - some compiler flags to prepare the code for interpretation; with `host`, this is not done. - This environment variable is useful to be sure that the compiled `rlib`s are compatible - with Miri. -* `MIRI_CALLED_FROM_SETUP` is set during the Miri sysroot build, - which will re-invoke `cargo-miri` as the `rustc` to use for this build. -* `MIRI_CALLED_FROM_RUSTDOC` when set to any value tells `cargo-miri` that it is - running as a child process of `rustdoc`, which invokes it twice for each doc-test - and requires special treatment, most notably a check-only build before interpretation. - This is set by `cargo-miri` itself when running as a `rustdoc`-wrapper. -* `MIRI_CWD` when set to any value tells the Miri driver to change to the given - directory after loading all the source files, but before commencing - interpretation. This is useful if the interpreted program wants a different - working directory at run-time than at build-time. -* `MIRI_LOCAL_CRATES` is set by `cargo-miri` to tell the Miri driver which - crates should be given special treatment in diagnostics, in addition to the - crate currently being compiled. -* `MIRI_ORIG_RUSTDOC` is set and read by different phases of `cargo-miri` to remember the - value of `RUSTDOC` from before it was overwritten. -* `MIRI_REPLACE_LIBRS_IF_NOT_TEST` when set to any value enables a hack that helps bootstrap - run the standard library tests in Miri. -* `MIRI_VERBOSE` when set to any value tells the various `cargo-miri` phases to - perform verbose logging. -* `MIRI_HOST_SYSROOT` is set by bootstrap to tell `cargo-miri` which sysroot to use for *host* - operations. - [testing-miri]: CONTRIBUTING.md#testing-the-miri-driver ## Miri `extern` functions diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 713c97830a5a2..f5fbb05d89622 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -31,24 +31,26 @@ time ./miri build --all-targets # the build that all the `./miri test` below wil endgroup # Run tests. Recognizes these variables: -# - MIRI_TEST_TARGET: the target to test. Empty for host target. +# - TEST_TARGET: the target to test. Empty for host target. # - GC_STRESS: if non-empty, run the GC stress test for the main test suite. # - MIR_OPT: if non-empty, re-run test `pass` tests with mir-opt-level=4 # - MANY_SEEDS: if set to N, run the "many-seeds" tests N times # - TEST_BENCH: if non-empty, check that the benchmarks all build # - CARGO_MIRI_ENV: if non-empty, set some env vars and config to potentially confuse cargo-miri function run_tests { - if [ -n "${MIRI_TEST_TARGET-}" ]; then - begingroup "Testing foreign architecture $MIRI_TEST_TARGET" + if [ -n "${TEST_TARGET-}" ]; then + begingroup "Testing foreign architecture $TEST_TARGET" + TARGET_FLAG="--target $TEST_TARGET" else begingroup "Testing host architecture" + TARGET_FLAG="" fi ## ui test suite if [ -n "${GC_STRESS-}" ]; then - time MIRIFLAGS="${MIRIFLAGS-} -Zmiri-provenance-gc=1" ./miri test + time MIRIFLAGS="${MIRIFLAGS-} -Zmiri-provenance-gc=1" ./miri test $TARGET_FLAG else - time ./miri test + time ./miri test $TARGET_FLAG fi ## advanced tests @@ -59,17 +61,17 @@ function run_tests { # them. Also error locations change so we don't run the failing tests. # We explicitly enable debug-assertions here, they are disabled by -O but we have tests # which exist to check that we panic on debug assertion failures. - time MIRIFLAGS="${MIRIFLAGS-} -O -Zmir-opt-level=4 -Cdebug-assertions=yes" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic} + time MIRIFLAGS="${MIRIFLAGS-} -O -Zmir-opt-level=4 -Cdebug-assertions=yes" MIRI_SKIP_UI_CHECKS=1 ./miri test $TARGET_FLAG tests/{pass,panic} fi if [ -n "${MANY_SEEDS-}" ]; then # Also run some many-seeds tests. time for FILE in tests/many-seeds/*.rs; do - ./miri run "--many-seeds=0..$MANY_SEEDS" "$FILE" + ./miri run "--many-seeds=0..$MANY_SEEDS" $TARGET_FLAG "$FILE" done fi if [ -n "${TEST_BENCH-}" ]; then # Check that the benchmarks build and run, but only once. - time HYPERFINE="hyperfine -w0 -r1" ./miri bench + time HYPERFINE="hyperfine -w0 -r1" ./miri bench $TARGET_FLAG fi ## test-cargo-miri @@ -91,7 +93,7 @@ function run_tests { echo 'build.rustc-wrapper = "thisdoesnotexist"' > .cargo/config.toml fi # Run the actual test - time ${PYTHON} test-cargo-miri/run-test.py + time ${PYTHON} test-cargo-miri/run-test.py $TARGET_FLAG # Clean up unset RUSTC MIRI rm -rf .cargo @@ -100,17 +102,18 @@ function run_tests { } function run_tests_minimal { - if [ -n "${MIRI_TEST_TARGET-}" ]; then - begingroup "Testing MINIMAL foreign architecture $MIRI_TEST_TARGET: only testing $@" + if [ -n "${TEST_TARGET-}" ]; then + begingroup "Testing MINIMAL foreign architecture $TEST_TARGET: only testing $@" + TARGET_FLAG="--target $TEST_TARGET" else - echo "run_tests_minimal requires MIRI_TEST_TARGET to be set" + echo "run_tests_minimal requires TEST_TARGET to be set" exit 1 fi - time ./miri test -- "$@" + time ./miri test $TARGET_FLAG "$@" # Ensure that a small smoke test of cargo-miri works. - time cargo miri run --manifest-path test-cargo-miri/no-std-smoke/Cargo.toml --target ${MIRI_TEST_TARGET-$HOST_TARGET} + time cargo miri run --manifest-path test-cargo-miri/no-std-smoke/Cargo.toml $TARGET_FLAG endgroup } @@ -126,34 +129,33 @@ case $HOST_TARGET in # Extra tier 1 # With reduced many-seed count to avoid spending too much time on that. # (All OSes and ABIs are run with 64 seeds at least once though via the macOS runner.) - MANY_SEEDS=16 MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests - MANY_SEEDS=16 MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests - MANY_SEEDS=16 MIRI_TEST_TARGET=x86_64-apple-darwin run_tests - MANY_SEEDS=16 MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests + MANY_SEEDS=16 TEST_TARGET=i686-unknown-linux-gnu run_tests + MANY_SEEDS=16 TEST_TARGET=aarch64-unknown-linux-gnu run_tests + MANY_SEEDS=16 TEST_TARGET=x86_64-apple-darwin run_tests + MANY_SEEDS=16 TEST_TARGET=x86_64-pc-windows-gnu run_tests ;; aarch64-apple-darwin) # Host (tier 2) GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests # Extra tier 1 - MANY_SEEDS=64 MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests - MANY_SEEDS=64 MIRI_TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests + MANY_SEEDS=64 TEST_TARGET=i686-pc-windows-gnu run_tests + MANY_SEEDS=64 TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests # Extra tier 2 - MIRI_TEST_TARGET=arm-unknown-linux-gnueabi run_tests - MIRI_TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice + TEST_TARGET=arm-unknown-linux-gnueabi run_tests + TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice # Partially supported targets (tier 2) VERY_BASIC="integer vec string btreemap" # common things we test on all of them (if they have std), requires no target-specific shims BASIC="$VERY_BASIC hello hashmap alloc align" # ensures we have the shims for stdout and basic data structures - MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC panic/panic concurrency/simple atomic threadname libc-misc libc-random libc-time fs env num_cpus - MIRI_TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC panic/panic concurrency/simple atomic threadname libc-misc libc-random libc-time fs env num_cpus - MIRI_TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $VERY_BASIC hello panic/panic concurrency/simple pthread-sync libc-misc libc-random - # TODO fix solaris stack guard - # MIRI_TEST_TARGET=x86_64-pc-solaris run_tests_minimal $VERY_BASIC hello panic/panic pthread-sync - MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal $VERY_BASIC hello panic/panic - MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal $VERY_BASIC wasm - MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal $VERY_BASIC wasm - MIRI_TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std + TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC panic/panic concurrency/simple atomic threadname libc-mem libc-misc libc-random libc-time fs env num_cpus + TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC panic/panic concurrency/simple atomic threadname libc-mem libc-misc libc-random libc-time fs env num_cpus + TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $VERY_BASIC hello panic/panic concurrency/simple pthread-sync libc-mem libc-misc libc-random + TEST_TARGET=x86_64-pc-solaris run_tests_minimal $VERY_BASIC hello panic/panic concurrency/simple pthread-sync libc-mem libc-misc libc-random + TEST_TARGET=aarch64-linux-android run_tests_minimal $VERY_BASIC hello panic/panic + TEST_TARGET=wasm32-wasi run_tests_minimal $VERY_BASIC wasm + TEST_TARGET=wasm32-unknown-unknown run_tests_minimal $VERY_BASIC wasm + TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std # Custom target JSON file - MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std + TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std ;; i686-pc-windows-msvc) # Host @@ -163,7 +165,7 @@ case $HOST_TARGET in # Extra tier 1 # We really want to ensure a Linux target works on a Windows host, # and a 64bit target works on a 32bit host. - MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests + TEST_TARGET=x86_64-unknown-linux-gnu run_tests ;; *) echo "FATAL: unknown host target: $HOST_TARGET" diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 6d07455c0deb6..8e2b07ad8052a 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -1,5 +1,5 @@ use std::env; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::io::Write; use std::ops::Not; use std::ops::Range; @@ -23,7 +23,9 @@ const JOSH_PORT: &str = "42042"; impl MiriEnv { /// Returns the location of the sysroot. - fn build_miri_sysroot(&mut self, quiet: bool) -> Result { + /// + /// If the target is None the sysroot will be built for the host machine. + fn build_miri_sysroot(&mut self, quiet: bool, target: Option<&OsStr>) -> Result { if let Some(miri_sysroot) = self.sh.var_os("MIRI_SYSROOT") { // Sysroot already set, use that. return Ok(miri_sysroot.into()); @@ -35,26 +37,28 @@ impl MiriEnv { self.build(path!(self.miri_dir / "Cargo.toml"), &[], quiet)?; self.build(&manifest_path, &[], quiet)?; - let target = &match self.sh.var("MIRI_TEST_TARGET") { - Ok(target) => vec!["--target".into(), target], - Err(_) => vec![], - }; + let target_flag = + if let Some(target) = target { vec![OsStr::new("--target"), target] } else { vec![] }; + let target_flag = &target_flag; + if !quiet { - match self.sh.var("MIRI_TEST_TARGET") { - Ok(target) => eprintln!("$ (building Miri sysroot for {target})"), - Err(_) => eprintln!("$ (building Miri sysroot)"), + if let Some(target) = target { + eprintln!("$ (building Miri sysroot for {})", target.to_string_lossy()); + } else { + eprintln!("$ (building Miri sysroot)"); } } + let output = cmd!(self.sh, "cargo +{toolchain} --quiet run {cargo_extra_flags...} --manifest-path {manifest_path} -- - miri setup --print-sysroot {target...}" + miri setup --print-sysroot {target_flag...}" ).read(); let Ok(output) = output else { // Run it again (without `--print-sysroot` or `--quiet`) so the user can see the error. cmd!( self.sh, "cargo +{toolchain} run {cargo_extra_flags...} --manifest-path {manifest_path} -- - miri setup {target...}" + miri setup {target_flag...}" ) .run() .with_context(|| "`cargo miri setup` failed")?; @@ -161,13 +165,13 @@ impl Command { Command::Install { flags } => Self::install(flags), Command::Build { flags } => Self::build(flags), Command::Check { flags } => Self::check(flags), - Command::Test { bless, flags } => Self::test(bless, flags), + Command::Test { bless, flags, target } => Self::test(bless, flags, target), Command::Run { dep, verbose, many_seeds, flags } => Self::run(dep, verbose, many_seeds, flags), Command::Fmt { flags } => Self::fmt(flags), Command::Clippy { flags } => Self::clippy(flags), Command::Cargo { flags } => Self::cargo(flags), - Command::Bench { benches } => Self::bench(benches), + Command::Bench { target, benches } => Self::bench(target, benches), Command::Toolchain { flags } => Self::toolchain(flags), Command::RustcPull { commit } => Self::rustc_pull(commit.clone()), Command::RustcPush { github_user, branch } => Self::rustc_push(github_user, branch), @@ -369,7 +373,7 @@ impl Command { Ok(()) } - fn bench(benches: Vec) -> Result<()> { + fn bench(target: Option, benches: Vec) -> Result<()> { // The hyperfine to use let hyperfine = env::var("HYPERFINE"); let hyperfine = hyperfine.as_deref().unwrap_or("hyperfine -w 1 -m 5 --shell=none"); @@ -377,8 +381,6 @@ impl Command { let Some((program_name, args)) = hyperfine.split_first() else { bail!("expected HYPERFINE environment variable to be non-empty"); }; - // Extra flags to pass to cargo. - let cargo_extra_flags = std::env::var("CARGO_EXTRA_FLAGS").unwrap_or_default(); // Make sure we have an up-to-date Miri installed and selected the right toolchain. Self::install(vec![])?; @@ -394,6 +396,14 @@ impl Command { } else { benches.to_owned() }; + let target_flag = if let Some(target) = target { + let mut flag = OsString::from("--target="); + flag.push(target); + flag + } else { + OsString::new() + }; + let target_flag = &target_flag; // Run the requested benchmarks for bench in benches { let current_bench = path!(benches_dir / bench / "Cargo.toml"); @@ -401,7 +411,7 @@ impl Command { // That seems to make Windows CI happy. cmd!( sh, - "{program_name} {args...} 'cargo miri run '{cargo_extra_flags}' --manifest-path \"'{current_bench}'\"'" + "{program_name} {args...} 'cargo miri run '{target_flag}' --manifest-path \"'{current_bench}'\"'" ) .run()?; } @@ -446,16 +456,26 @@ impl Command { Ok(()) } - fn test(bless: bool, flags: Vec) -> Result<()> { + fn test(bless: bool, mut flags: Vec, target: Option) -> Result<()> { let mut e = MiriEnv::new()?; + // Prepare a sysroot. - e.build_miri_sysroot(/* quiet */ false)?; + e.build_miri_sysroot(/* quiet */ false, target.as_deref())?; - // Then test, and let caller control flags. - // Only in root project as `cargo-miri` has no tests. + // Forward information to test harness. if bless { e.sh.set_var("RUSTC_BLESS", "Gesundheit"); } + if let Some(target) = target { + // Tell the harness which target to test. + e.sh.set_var("MIRI_TEST_TARGET", target); + } + + // Make sure the flags are going to the test harness, not cargo. + flags.insert(0, "--".into()); + + // Then test, and let caller control flags. + // Only in root project as `cargo-miri` has no tests. e.test(path!(e.miri_dir / "Cargo.toml"), &flags)?; Ok(()) } @@ -467,32 +487,16 @@ impl Command { mut flags: Vec, ) -> Result<()> { let mut e = MiriEnv::new()?; - // Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so - // that we set the MIRI_SYSROOT up the right way. We must make sure that - // MIRI_TEST_TARGET and `--target` are in sync. - use itertools::Itertools; - let target = flags - .iter() - .take_while(|arg| *arg != "--") - .tuple_windows() - .find(|(first, _)| *first == "--target"); - if let Some((_, target)) = target { - // Found it! - e.sh.set_var("MIRI_TEST_TARGET", target); - } else if let Ok(target) = std::env::var("MIRI_TEST_TARGET") { - // Convert `MIRI_TEST_TARGET` into `--target`. - flags.push("--target".into()); - flags.push(target.into()); - } + let target = arg_flag_value(&flags, "--target"); + // Scan for "--edition", set one ourselves if that flag is not present. - let have_edition = - flags.iter().take_while(|arg| *arg != "--").any(|arg| *arg == "--edition"); + let have_edition = arg_flag_value(&flags, "--edition").is_some(); if !have_edition { flags.push("--edition=2021".into()); // keep in sync with `tests/ui.rs`.` } // Prepare a sysroot, and add it to the flags. - let miri_sysroot = e.build_miri_sysroot(/* quiet */ !verbose)?; + let miri_sysroot = e.build_miri_sysroot(/* quiet */ !verbose, target.as_deref())?; flags.push("--sysroot".into()); flags.push(miri_sysroot.into()); diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs index f0ebbc846906e..a8626ceb45d75 100644 --- a/src/tools/miri/miri-script/src/main.rs +++ b/src/tools/miri/miri-script/src/main.rs @@ -31,7 +31,10 @@ pub enum Command { /// Build miri, set up a sysroot and then run the test suite. Test { bless: bool, - /// Flags that are passed through to `cargo test`. + /// The cross-interpretation target. + /// If none then the host is the target. + target: Option, + /// Flags that are passed through to the test harness. flags: Vec, }, /// Build miri, set up a sysroot and then run the driver with the given . @@ -58,6 +61,7 @@ pub enum Command { Cargo { flags: Vec }, /// Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed. Bench { + target: Option, /// List of benchmarks to run. By default all benchmarks are run. benches: Vec, }, @@ -84,9 +88,9 @@ Just build miri. are passed to `cargo build`. ./miri check : Just check miri. are passed to `cargo check`. -./miri test [--bless] : -Build miri, set up a sysroot and then run the test suite. are passed -to the final `cargo test` invocation. +./miri test [--bless] [--target ] : +Build miri, set up a sysroot and then run the test suite. + are passed to the test harness. ./miri run [--dep] [-v|--verbose] [--many-seeds|--many-seeds=..to|--many-seeds=from..to] : Build miri, set up a sysroot and then run the driver with the given . @@ -110,7 +114,7 @@ install`. Sets up the rpath such that the installed binary should work in any working directory. Note that the binaries are placed in the `miri` toolchain sysroot, to prevent conflicts with other toolchains. -./miri bench : +./miri bench [--target ] : Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed. can explicitly list the benchmarks to run; by default, all of them are run. @@ -147,12 +151,30 @@ fn main() -> Result<()> { Some("build") => Command::Build { flags: args.collect() }, Some("check") => Command::Check { flags: args.collect() }, Some("test") => { - let bless = args.peek().is_some_and(|a| a.to_str() == Some("--bless")); - if bless { - // Consume the flag. + let mut target = None; + let mut bless = false; + + while let Some(arg) = args.peek().and_then(|s| s.to_str()) { + match arg { + "--bless" => bless = true, + "--target" => { + // Skip "--target" + args.next().unwrap(); + // Next argument is the target triple. + let val = args.peek().ok_or_else(|| { + anyhow!("`--target` must be followed by target triple") + })?; + target = Some(val.to_owned()); + } + // Only parse the leading flags. + _ => break, + } + + // Consume the flag, look at the next one. args.next().unwrap(); } - Command::Test { bless, flags: args.collect() } + + Command::Test { bless, flags: args.collect(), target } } Some("run") => { let mut dep = false; @@ -188,7 +210,29 @@ fn main() -> Result<()> { Some("clippy") => Command::Clippy { flags: args.collect() }, Some("cargo") => Command::Cargo { flags: args.collect() }, Some("install") => Command::Install { flags: args.collect() }, - Some("bench") => Command::Bench { benches: args.collect() }, + Some("bench") => { + let mut target = None; + while let Some(arg) = args.peek().and_then(|s| s.to_str()) { + match arg { + "--target" => { + // Skip "--target" + args.next().unwrap(); + // Next argument is the target triple. + let val = args.peek().ok_or_else(|| { + anyhow!("`--target` must be followed by target triple") + })?; + target = Some(val.to_owned()); + } + // Only parse the leading flags. + _ => break, + } + + // Consume the flag, look at the next one. + args.next().unwrap(); + } + + Command::Bench { target, benches: args.collect() } + } Some("toolchain") => Command::Toolchain { flags: args.collect() }, Some("rustc-pull") => { let commit = args.next().map(|a| a.to_string_lossy().into_owned()); diff --git a/src/tools/miri/miri-script/src/util.rs b/src/tools/miri/miri-script/src/util.rs index 23b5e936edd81..2b5791f3ea53d 100644 --- a/src/tools/miri/miri-script/src/util.rs +++ b/src/tools/miri/miri-script/src/util.rs @@ -27,6 +27,30 @@ pub fn flagsplit(flags: &str) -> Vec { flags.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string).collect() } +pub fn arg_flag_value( + args: impl IntoIterator>, + flag: &str, +) -> Option { + let mut args = args.into_iter(); + while let Some(arg) = args.next() { + let arg = arg.as_ref(); + if arg == "--" { + return None; + } + let Some(arg) = arg.to_str() else { + // Skip non-UTF-8 arguments. + continue; + }; + if arg == flag { + // Next one is the value. + return Some(args.next()?.as_ref().to_owned()); + } else if let Some(val) = arg.strip_prefix(flag).and_then(|s| s.strip_prefix("=")) { + return Some(val.to_owned().into()); + } + } + None +} + /// Some extra state we track for building Miri, such as the right RUSTFLAGS. pub struct MiriEnv { /// miri_dir is the root of the miri repository checkout we are working in. diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index ca6f4d50917e9..3636c856d0b55 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -d568423a7a4ddb4b49323d96078a22f94df55fbd +ef15976387ad9c1cdceaabf469e0cf35f5852f6d diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 44201cb89ae79..305e9cd8d3428 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -575,18 +575,15 @@ fn main() { "full" => BacktraceStyle::Full, _ => show_error!("-Zmiri-backtrace may only be 0, 1, or full"), }; - } else if let Some(param) = arg.strip_prefix("-Zmiri-extern-so-file=") { + } else if let Some(param) = arg.strip_prefix("-Zmiri-native-lib=") { let filename = param.to_string(); if std::path::Path::new(&filename).exists() { - if let Some(other_filename) = miri_config.external_so_file { - show_error!( - "-Zmiri-extern-so-file is already set to {}", - other_filename.display() - ); + if let Some(other_filename) = miri_config.native_lib { + show_error!("-Zmiri-native-lib is already set to {}", other_filename.display()); } - miri_config.external_so_file = Some(filename.into()); + miri_config.native_lib = Some(filename.into()); } else { - show_error!("-Zmiri-extern-so-file `{}` does not exist", filename); + show_error!("-Zmiri-native-lib `{}` does not exist", filename); } } else if let Some(param) = arg.strip_prefix("-Zmiri-num-cpus=") { let num_cpus = param diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index a6dd1d829cb4f..3da8744626d72 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -136,7 +136,7 @@ impl NewPermission { cx: &crate::MiriInterpCx<'_, 'tcx>, ) -> Self { // `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling). - let pointee = ty.builtin_deref(true).unwrap().ty; + let pointee = ty.builtin_deref(true).unwrap(); if pointee.is_unpin(*cx.tcx, cx.param_env()) { // A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only // a weak protector). diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index fc5eb942a27b5..b5bf16d3d3665 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -173,7 +173,7 @@ impl<'tcx> NewPermission { cx: &crate::MiriInterpCx<'_, 'tcx>, zero_size: bool, ) -> Option { - let pointee = ty.builtin_deref(true).unwrap().ty; + let pointee = ty.builtin_deref(true).unwrap(); pointee.is_unpin(*cx.tcx, cx.param_env()).then_some(()).map(|()| { // Regular `Unpin` box, give it `noalias` but only a weak protector // because it is valid to deallocate it within the function. diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 97c5e9a0eac97..78c092faf9097 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -142,8 +142,8 @@ pub struct MiriConfig { /// Whether Stacked Borrows and Tree Borrows retagging should recurse into fields of datatypes. pub retag_fields: RetagFields, /// The location of a shared object file to load when calling external functions - /// FIXME! consider allowing users to specify paths to multiple SO files, or to a directory - pub external_so_file: Option, + /// FIXME! consider allowing users to specify paths to multiple files, or to a directory + pub native_lib: Option, /// Run a garbage collector for BorTags every N basic blocks. pub gc_interval: u32, /// The number of CPUs to be reported by miri. @@ -188,7 +188,7 @@ impl Default for MiriConfig { preemption_rate: 0.01, // 1% report_progress: None, retag_fields: RetagFields::Yes, - external_so_file: None, + native_lib: None, gc_interval: 10_000, num_cpus: 1, page_size: None, diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 40c2008ac9435..4050ae3c4bf97 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -751,26 +751,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { /// This function tries to produce the most similar OS error from the `std::io::ErrorKind` /// as a platform-specific errnum. - fn io_error_to_errnum( - &self, - err_kind: std::io::ErrorKind, - ) -> InterpResult<'tcx, Scalar> { + fn io_error_to_errnum(&self, err: std::io::Error) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); let target = &this.tcx.sess.target; if target.families.iter().any(|f| f == "unix") { for &(name, kind) in UNIX_IO_ERROR_TABLE { - if err_kind == kind { + if err.kind() == kind { return Ok(this.eval_libc(name)); } } - throw_unsup_format!("io error {:?} cannot be translated into a raw os error", err_kind) + throw_unsup_format!("unsupported io error: {err}") } else if target.families.iter().any(|f| f == "windows") { for &(name, kind) in WINDOWS_IO_ERROR_TABLE { - if err_kind == kind { + if err.kind() == kind { return Ok(this.eval_windows("c", name)); } } - throw_unsup_format!("io error {:?} cannot be translated into a raw os error", err_kind); + throw_unsup_format!("unsupported io error: {err}"); } else { throw_unsup_format!( "converting io::Error into errnum is unsupported for OS {}", @@ -812,8 +809,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } /// Sets the last OS error using a `std::io::ErrorKind`. - fn set_last_error_from_io_error(&mut self, err_kind: std::io::ErrorKind) -> InterpResult<'tcx> { - self.set_last_error(self.io_error_to_errnum(err_kind)?) + fn set_last_error_from_io_error(&mut self, err: std::io::Error) -> InterpResult<'tcx> { + self.set_last_error(self.io_error_to_errnum(err)?) } /// Helper function that consumes an `std::io::Result` and returns an @@ -829,7 +826,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { match result { Ok(ok) => Ok(ok), Err(e) => { - self.eval_context_mut().set_last_error_from_io_error(e.kind())?; + self.eval_context_mut().set_last_error_from_io_error(e)?; Ok((-1).into()) } } @@ -982,29 +979,46 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok((true, string_length)) } - /// Read a sequence of u16 until the first null terminator. - fn read_wide_str(&self, mut ptr: Pointer>) -> InterpResult<'tcx, Vec> { + /// Helper function to read a sequence of unsigned integers of the given size and alignment + /// until the first null terminator. + fn read_c_str_with_char_size( + &self, + mut ptr: Pointer>, + size: Size, + align: Align, + ) -> InterpResult<'tcx, Vec> + where + T: TryFrom, + >::Error: std::fmt::Debug, + { + assert_ne!(size, Size::ZERO); + let this = self.eval_context_ref(); - let size2 = Size::from_bytes(2); - this.check_ptr_align(ptr, Align::from_bytes(2).unwrap())?; + + this.check_ptr_align(ptr, align)?; let mut wchars = Vec::new(); loop { // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. - let alloc = this.get_ptr_alloc(ptr, size2)?.unwrap(); // not a ZST, so we will get a result - let wchar = alloc.read_integer(alloc_range(Size::ZERO, size2))?.to_u16()?; - if wchar == 0 { + let alloc = this.get_ptr_alloc(ptr, size)?.unwrap(); // not a ZST, so we will get a result + let wchar_int = alloc.read_integer(alloc_range(Size::ZERO, size))?.to_bits(size)?; + if wchar_int == 0 { break; } else { - wchars.push(wchar); - ptr = ptr.offset(size2, this)?; + wchars.push(wchar_int.try_into().unwrap()); + ptr = ptr.offset(size, this)?; } } Ok(wchars) } + /// Read a sequence of u16 until the first null terminator. + fn read_wide_str(&self, ptr: Pointer>) -> InterpResult<'tcx, Vec> { + self.read_c_str_with_char_size(ptr, Size::from_bytes(2), Align::from_bytes(2).unwrap()) + } + /// Helper function to write a sequence of u16 with an added 0x0000-terminator, which is what /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null @@ -1037,6 +1051,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok((true, string_length)) } + /// Read a sequence of wchar_t until the first null terminator. + /// Always returns a `Vec` no matter the size of `wchar_t`. + fn read_wchar_t_str(&self, ptr: Pointer>) -> InterpResult<'tcx, Vec> { + let this = self.eval_context_ref(); + let wchar_t = this.libc_ty_layout("wchar_t"); + self.read_c_str_with_char_size(ptr, wchar_t.size, wchar_t.align.abi) + } + /// Check that the ABI is what we expect. fn check_abi<'a>(&self, abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> { if abi != exp_abi { diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index effd7f6d5435f..9e7fc7a21fcb4 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -117,7 +117,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "write_bytes" | "volatile_set_memory" => { let [ptr, val_byte, count] = check_arg_count(args)?; - let ty = ptr.layout.ty.builtin_deref(true).unwrap().ty; + let ty = ptr.layout.ty.builtin_deref(true).unwrap(); let ty_layout = this.layout_of(ty)?; let val_byte = this.read_scalar(val_byte)?.to_u8()?; let ptr = this.read_pointer(ptr)?; diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index 3be98d7f5f864..d0a78429ca851 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -267,7 +267,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Op::WrappingOffset => { let ptr = left.to_scalar().to_pointer(this)?; let offset_count = right.to_scalar().to_target_isize(this)?; - let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; + let pointee_ty = left.layout.ty.builtin_deref(true).unwrap(); let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); let offset_bytes = offset_count.wrapping_mul(pointee_size); diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 1680b98eca33f..54eb6a3bd6699 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -12,6 +12,7 @@ #![feature(let_chains)] #![feature(lint_reasons)] #![feature(trait_upcasting)] +#![feature(strict_overflow_ops)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 51b96bff5fefc..8854b18528034 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -535,11 +535,11 @@ pub struct MiriMachine<'mir, 'tcx> { // The total number of blocks that have been executed. pub(crate) basic_block_count: u64, - /// Handle of the optional shared object file for external functions. + /// Handle of the optional shared object file for native functions. #[cfg(target_os = "linux")] - pub external_so_lib: Option<(libloading::Library, std::path::PathBuf)>, + pub native_lib: Option<(libloading::Library, std::path::PathBuf)>, #[cfg(not(target_os = "linux"))] - pub external_so_lib: Option, + pub native_lib: Option, /// Run a garbage collector for BorTags every N basic blocks. pub(crate) gc_interval: u32, @@ -665,7 +665,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { basic_block_count: 0, clock: Clock::new(config.isolated_op == IsolatedOp::Allow), #[cfg(target_os = "linux")] - external_so_lib: config.external_so_file.as_ref().map(|lib_file_path| { + native_lib: config.native_lib.as_ref().map(|lib_file_path| { let target_triple = layout_cx.tcx.sess.opts.target_triple.triple(); // Check if host target == the session target. if env!("TARGET") != target_triple { @@ -687,7 +687,7 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { ) }), #[cfg(not(target_os = "linux"))] - external_so_lib: config.external_so_file.as_ref().map(|_| { + native_lib: config.native_lib.as_ref().map(|_| { panic!("loading external .so files is only supported on Linux") }), gc_interval: config.gc_interval, @@ -802,7 +802,7 @@ impl VisitProvenance for MiriMachine<'_, '_> { preemption_rate: _, report_progress: _, basic_block_count: _, - external_so_lib: _, + native_lib: _, gc_interval: _, since_gc: _, num_cpus: _, diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs index 79531598c003a..1deb9a5654edf 100644 --- a/src/tools/miri/src/shims/alloc.rs +++ b/src/tools/miri/src/shims/alloc.rs @@ -19,22 +19,36 @@ pub(super) fn check_alloc_request<'tcx>(size: u64, align: u64) -> InterpResult<' impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - /// Returns the minimum alignment for the target architecture for allocations of the given size. - fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align { + /// Returns the alignment that `malloc` would guarantee for requests of the given size. + fn malloc_align(&self, size: u64) -> Align { let this = self.eval_context_ref(); - // List taken from `library/std/src/sys/pal/common/alloc.rs`. - // This list should be kept in sync with the one from libstd. - let min_align = match this.tcx.sess.target.arch.as_ref() { + // The C standard says: "The pointer returned if the allocation succeeds is suitably aligned + // so that it may be assigned to a pointer to any type of object with a fundamental + // alignment requirement and size less than or equal to the size requested." + // So first we need to figure out what the limits are for "fundamental alignment". + // This is given by `alignof(max_align_t)`. The following list is taken from + // `library/std/src/sys/pal/common/alloc.rs` (where this is called `MIN_ALIGN`) and should + // be kept in sync. + let max_fundamental_align = match this.tcx.sess.target.arch.as_ref() { "x86" | "arm" | "mips" | "mips32r6" | "powerpc" | "powerpc64" | "wasm32" => 8, "x86_64" | "aarch64" | "mips64" | "mips64r6" | "s390x" | "sparc64" | "loongarch64" => 16, arch => bug!("unsupported target architecture for malloc: `{}`", arch), }; - // Windows always aligns, even small allocations. - // Source: - // But jemalloc does not, so for the C heap we only align if the allocation is sufficiently big. - if kind == MiriMemoryKind::WinHeap || size >= min_align { - return Align::from_bytes(min_align).unwrap(); + // The C standard only requires sufficient alignment for any *type* with size less than or + // equal to the size requested. Types one can define in standard C seem to never have an alignment + // bigger than their size. So if the size is 2, then only alignment 2 is guaranteed, even if + // `max_fundamental_align` is bigger. + // This matches what some real-world implementations do, see e.g. + // - https://github.com/jemalloc/jemalloc/issues/1533 + // - https://github.com/llvm/llvm-project/issues/53540 + // - https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2293.htm + if size >= max_fundamental_align { + return Align::from_bytes(max_fundamental_align).unwrap(); + } + // C doesn't have zero-sized types, so presumably nothing is guaranteed here. + if size == 0 { + return Align::ONE; } // We have `size < min_align`. Round `size` *down* to the next power of two and use that. fn prev_power_of_two(x: u64) -> u64 { @@ -82,34 +96,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { &mut self, size: u64, zero_init: bool, - kind: MiriMemoryKind, ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); - if size == 0 { - Ok(Pointer::null()) - } else { - let align = this.min_align(size, kind); - let ptr = this.allocate_ptr(Size::from_bytes(size), align, kind.into())?; - if zero_init { - // We just allocated this, the access is definitely in-bounds and fits into our address space. - this.write_bytes_ptr( - ptr.into(), - iter::repeat(0u8).take(usize::try_from(size).unwrap()), - ) - .unwrap(); - } - Ok(ptr.into()) + let align = this.malloc_align(size); + let ptr = this.allocate_ptr(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; + if zero_init { + // We just allocated this, the access is definitely in-bounds and fits into our address space. + this.write_bytes_ptr( + ptr.into(), + iter::repeat(0u8).take(usize::try_from(size).unwrap()), + ) + .unwrap(); } + Ok(ptr.into()) } - fn free( - &mut self, - ptr: Pointer>, - kind: MiriMemoryKind, - ) -> InterpResult<'tcx> { + fn free(&mut self, ptr: Pointer>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if !this.ptr_is_null(ptr)? { - this.deallocate_ptr(ptr, None, kind.into())?; + this.deallocate_ptr(ptr, None, MiriMemoryKind::C.into())?; } Ok(()) } @@ -118,19 +123,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { &mut self, old_ptr: Pointer>, new_size: u64, - kind: MiriMemoryKind, ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); - let new_align = this.min_align(new_size, kind); + let new_align = this.malloc_align(new_size); if this.ptr_is_null(old_ptr)? { // Here we must behave like `malloc`. - if new_size == 0 { - Ok(Pointer::null()) - } else { - let new_ptr = - this.allocate_ptr(Size::from_bytes(new_size), new_align, kind.into())?; - Ok(new_ptr.into()) - } + self.malloc(new_size, /*zero_init*/ false) } else { if new_size == 0 { // C, in their infinite wisdom, made this UB. @@ -142,7 +140,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { None, Size::from_bytes(new_size), new_align, - kind.into(), + MiriMemoryKind::C.into(), )?; Ok(new_ptr.into()) } diff --git a/src/tools/miri/src/shims/ffi_support.rs b/src/tools/miri/src/shims/ffi_support.rs deleted file mode 100644 index 6da119e5fa8fb..0000000000000 --- a/src/tools/miri/src/shims/ffi_support.rs +++ /dev/null @@ -1,289 +0,0 @@ -use libffi::{high::call as ffi, low::CodePtr}; -use std::ops::Deref; - -use rustc_middle::ty::{self as ty, IntTy, Ty, UintTy}; -use rustc_span::Symbol; -use rustc_target::abi::HasDataLayout; - -use crate::*; - -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} - -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { - /// Extract the scalar value from the result of reading a scalar from the machine, - /// and convert it to a `CArg`. - fn scalar_to_carg( - k: Scalar, - arg_type: Ty<'tcx>, - cx: &impl HasDataLayout, - ) -> InterpResult<'tcx, CArg> { - match arg_type.kind() { - // If the primitive provided can be converted to a type matching the type pattern - // then create a `CArg` of this primitive value with the corresponding `CArg` constructor. - // the ints - ty::Int(IntTy::I8) => { - return Ok(CArg::Int8(k.to_i8()?)); - } - ty::Int(IntTy::I16) => { - return Ok(CArg::Int16(k.to_i16()?)); - } - ty::Int(IntTy::I32) => { - return Ok(CArg::Int32(k.to_i32()?)); - } - ty::Int(IntTy::I64) => { - return Ok(CArg::Int64(k.to_i64()?)); - } - ty::Int(IntTy::Isize) => { - // This will fail if host != target, but then the entire FFI thing probably won't work well - // in that situation. - return Ok(CArg::ISize(k.to_target_isize(cx)?.try_into().unwrap())); - } - // the uints - ty::Uint(UintTy::U8) => { - return Ok(CArg::UInt8(k.to_u8()?)); - } - ty::Uint(UintTy::U16) => { - return Ok(CArg::UInt16(k.to_u16()?)); - } - ty::Uint(UintTy::U32) => { - return Ok(CArg::UInt32(k.to_u32()?)); - } - ty::Uint(UintTy::U64) => { - return Ok(CArg::UInt64(k.to_u64()?)); - } - ty::Uint(UintTy::Usize) => { - // This will fail if host != target, but then the entire FFI thing probably won't work well - // in that situation. - return Ok(CArg::USize(k.to_target_usize(cx)?.try_into().unwrap())); - } - _ => {} - } - // If no primitives were returned then we have an unsupported type. - throw_unsup_format!( - "unsupported scalar argument type to external C function: {:?}", - arg_type - ); - } - - /// Call external C function and - /// store output, depending on return type in the function signature. - fn call_external_c_and_store_return<'a>( - &mut self, - link_name: Symbol, - dest: &MPlaceTy<'tcx, Provenance>, - ptr: CodePtr, - libffi_args: Vec>, - ) -> InterpResult<'tcx, ()> { - let this = self.eval_context_mut(); - - // Unsafe because of the call to external C code. - // Because this is calling a C function it is not necessarily sound, - // but there is no way around this and we've checked as much as we can. - unsafe { - // If the return type of a function is a primitive integer type, - // then call the function (`ptr`) with arguments `libffi_args`, store the return value as the specified - // primitive integer type, and then write this value out to the miri memory as an integer. - match dest.layout.ty.kind() { - // ints - ty::Int(IntTy::I8) => { - let x = ffi::call::(ptr, libffi_args.as_slice()); - this.write_int(x, dest)?; - return Ok(()); - } - ty::Int(IntTy::I16) => { - let x = ffi::call::(ptr, libffi_args.as_slice()); - this.write_int(x, dest)?; - return Ok(()); - } - ty::Int(IntTy::I32) => { - let x = ffi::call::(ptr, libffi_args.as_slice()); - this.write_int(x, dest)?; - return Ok(()); - } - ty::Int(IntTy::I64) => { - let x = ffi::call::(ptr, libffi_args.as_slice()); - this.write_int(x, dest)?; - return Ok(()); - } - ty::Int(IntTy::Isize) => { - let x = ffi::call::(ptr, libffi_args.as_slice()); - // `isize` doesn't `impl Into`, so convert manually. - // Convert to `i64` since this covers both 32- and 64-bit machines. - this.write_int(i64::try_from(x).unwrap(), dest)?; - return Ok(()); - } - // uints - ty::Uint(UintTy::U8) => { - let x = ffi::call::(ptr, libffi_args.as_slice()); - this.write_int(x, dest)?; - return Ok(()); - } - ty::Uint(UintTy::U16) => { - let x = ffi::call::(ptr, libffi_args.as_slice()); - this.write_int(x, dest)?; - return Ok(()); - } - ty::Uint(UintTy::U32) => { - let x = ffi::call::(ptr, libffi_args.as_slice()); - this.write_int(x, dest)?; - return Ok(()); - } - ty::Uint(UintTy::U64) => { - let x = ffi::call::(ptr, libffi_args.as_slice()); - this.write_int(x, dest)?; - return Ok(()); - } - ty::Uint(UintTy::Usize) => { - let x = ffi::call::(ptr, libffi_args.as_slice()); - // `usize` doesn't `impl Into`, so convert manually. - // Convert to `u64` since this covers both 32- and 64-bit machines. - this.write_int(u64::try_from(x).unwrap(), dest)?; - return Ok(()); - } - // Functions with no declared return type (i.e., the default return) - // have the output_type `Tuple([])`. - ty::Tuple(t_list) => - if t_list.len() == 0 { - ffi::call::<()>(ptr, libffi_args.as_slice()); - return Ok(()); - }, - _ => {} - } - // FIXME ellen! deal with all the other return types - throw_unsup_format!("unsupported return type to external C function: {:?}", link_name); - } - } - - /// Get the pointer to the function of the specified name in the shared object file, - /// if it exists. The function must be in the shared object file specified: we do *not* - /// return pointers to functions in dependencies of the library. - fn get_func_ptr_explicitly_from_lib(&mut self, link_name: Symbol) -> Option { - let this = self.eval_context_mut(); - // Try getting the function from the shared library. - // On windows `_lib_path` will be unused, hence the name starting with `_`. - let (lib, _lib_path) = this.machine.external_so_lib.as_ref().unwrap(); - let func: libloading::Symbol<'_, unsafe extern "C" fn()> = unsafe { - match lib.get(link_name.as_str().as_bytes()) { - Ok(x) => x, - Err(_) => { - return None; - } - } - }; - - // FIXME: this is a hack! - // The `libloading` crate will automatically load system libraries like `libc`. - // On linux `libloading` is based on `dlsym`: https://docs.rs/libloading/0.7.3/src/libloading/os/unix/mod.rs.html#202 - // and `dlsym`(https://linux.die.net/man/3/dlsym) looks through the dependency tree of the - // library if it can't find the symbol in the library itself. - // So, in order to check if the function was actually found in the specified - // `machine.external_so_lib` we need to check its `dli_fname` and compare it to - // the specified SO file path. - // This code is a reimplementation of the mechanism for getting `dli_fname` in `libloading`, - // from: https://docs.rs/libloading/0.7.3/src/libloading/os/unix/mod.rs.html#411 - // using the `libc` crate where this interface is public. - // No `libc::dladdr` on windows. - let mut info = std::mem::MaybeUninit::::uninit(); - unsafe { - if libc::dladdr(*func.deref() as *const _, info.as_mut_ptr()) != 0 { - if std::ffi::CStr::from_ptr(info.assume_init().dli_fname).to_str().unwrap() - != _lib_path.to_str().unwrap() - { - return None; - } - } - } - // Return a pointer to the function. - Some(CodePtr(*func.deref() as *mut _)) - } - - /// Call specified external C function, with supplied arguments. - /// Need to convert all the arguments from their hir representations to - /// a form compatible with C (through `libffi` call). - /// Then, convert return from the C call into a corresponding form that - /// can be stored in Miri internal memory. - fn call_external_c_fct( - &mut self, - link_name: Symbol, - dest: &MPlaceTy<'tcx, Provenance>, - args: &[OpTy<'tcx, Provenance>], - ) -> InterpResult<'tcx, bool> { - // Get the pointer to the function in the shared object file if it exists. - let code_ptr = match self.get_func_ptr_explicitly_from_lib(link_name) { - Some(ptr) => ptr, - None => { - // Shared object file does not export this function -- try the shims next. - return Ok(false); - } - }; - - let this = self.eval_context_mut(); - - // Get the function arguments, and convert them to `libffi`-compatible form. - let mut libffi_args = Vec::::with_capacity(args.len()); - for cur_arg in args.iter() { - libffi_args.push(Self::scalar_to_carg( - this.read_scalar(cur_arg)?, - cur_arg.layout.ty, - this, - )?); - } - - // Convert them to `libffi::high::Arg` type. - let libffi_args = libffi_args - .iter() - .map(|cur_arg| cur_arg.arg_downcast()) - .collect::>>(); - - // Call the function and store output, depending on return type in the function signature. - self.call_external_c_and_store_return(link_name, dest, code_ptr, libffi_args)?; - Ok(true) - } -} - -#[derive(Debug, Clone)] -/// Enum of supported arguments to external C functions. -// We introduce this enum instead of just calling `ffi::arg` and storing a list -// of `libffi::high::Arg` directly, because the `libffi::high::Arg` just wraps a reference -// to the value it represents: https://docs.rs/libffi/latest/libffi/high/call/struct.Arg.html -// and we need to store a copy of the value, and pass a reference to this copy to C instead. -pub enum CArg { - /// 8-bit signed integer. - Int8(i8), - /// 16-bit signed integer. - Int16(i16), - /// 32-bit signed integer. - Int32(i32), - /// 64-bit signed integer. - Int64(i64), - /// isize. - ISize(isize), - /// 8-bit unsigned integer. - UInt8(u8), - /// 16-bit unsigned integer. - UInt16(u16), - /// 32-bit unsigned integer. - UInt32(u32), - /// 64-bit unsigned integer. - UInt64(u64), - /// usize. - USize(usize), -} - -impl<'a> CArg { - /// Convert a `CArg` to a `libffi` argument type. - fn arg_downcast(&'a self) -> libffi::high::Arg<'a> { - match self { - CArg::Int8(i) => ffi::arg(i), - CArg::Int16(i) => ffi::arg(i), - CArg::Int32(i) => ffi::arg(i), - CArg::Int64(i) => ffi::arg(i), - CArg::ISize(i) => ffi::arg(i), - CArg::UInt8(i) => ffi::arg(i), - CArg::UInt16(i) => ffi::arg(i), - CArg::UInt32(i) => ffi::arg(i), - CArg::UInt64(i) => ffi::arg(i), - CArg::USize(i) => ffi::arg(i), - } - } -} diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index c51a27b7458a8..d431c28d55a56 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -211,12 +211,12 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // First deal with any external C functions in linked .so file. #[cfg(target_os = "linux")] - if this.machine.external_so_lib.as_ref().is_some() { - use crate::shims::ffi_support::EvalContextExt as _; + if this.machine.native_lib.as_ref().is_some() { + use crate::shims::native_lib::EvalContextExt as _; // An Ok(false) here means that the function being called was not exported // by the specified `.so` file; we should continue and check if it corresponds to // a provided shim. - if this.call_external_c_fct(link_name, dest, args)? { + if this.call_native_fn(link_name, dest, args)? { return Ok(EmulateItemResult::NeedsJumping); } } @@ -421,7 +421,7 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "malloc" => { let [size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let size = this.read_target_usize(size)?; - let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C)?; + let res = this.malloc(size, /*zero_init:*/ false)?; this.write_pointer(res, dest)?; } "calloc" => { @@ -432,20 +432,20 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let size = items .checked_mul(len) .ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?; - let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C)?; + let res = this.malloc(size, /*zero_init:*/ true)?; this.write_pointer(res, dest)?; } "free" => { let [ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_pointer(ptr)?; - this.free(ptr, MiriMemoryKind::C)?; + this.free(ptr)?; } "realloc" => { let [old_ptr, new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let old_ptr = this.read_pointer(old_ptr)?; let new_size = this.read_target_usize(new_size)?; - let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; + let res = this.realloc(old_ptr, new_size)?; this.write_pointer(res, dest)?; } @@ -657,6 +657,16 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { dest, )?; } + "wcslen" => { + let [ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let ptr = this.read_pointer(ptr)?; + // This reads at least 1 byte, so we are already enforcing that this is a valid pointer. + let n = this.read_wchar_t_str(ptr)?.len(); + this.write_scalar( + Scalar::from_target_usize(u64::try_from(n).unwrap(), this), + dest, + )?; + } "memcpy" => { let [ptr_dest, ptr_src, n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs index 11048459206bf..aaa3c69b92da7 100644 --- a/src/tools/miri/src/shims/mod.rs +++ b/src/tools/miri/src/shims/mod.rs @@ -2,9 +2,9 @@ mod alloc; mod backtrace; -#[cfg(target_os = "linux")] -pub mod ffi_support; pub mod foreign_items; +#[cfg(target_os = "linux")] +pub mod native_lib; pub mod unix; pub mod windows; mod x86; diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs new file mode 100644 index 0000000000000..f9b8563b4b04e --- /dev/null +++ b/src/tools/miri/src/shims/native_lib.rs @@ -0,0 +1,242 @@ +//! Implements calling functions from a native library. +use libffi::{high::call as ffi, low::CodePtr}; +use std::ops::Deref; + +use rustc_middle::ty::{self as ty, IntTy, UintTy}; +use rustc_span::Symbol; +use rustc_target::abi::{Abi, HasDataLayout}; + +use crate::*; + +impl<'mir, 'tcx: 'mir> EvalContextExtPriv<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { + /// Call native host function and return the output as an immediate. + fn call_native_with_args<'a>( + &mut self, + link_name: Symbol, + dest: &MPlaceTy<'tcx, Provenance>, + ptr: CodePtr, + libffi_args: Vec>, + ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + let this = self.eval_context_mut(); + + // Call the function (`ptr`) with arguments `libffi_args`, and obtain the return value + // as the specified primitive integer type + let scalar = match dest.layout.ty.kind() { + // ints + ty::Int(IntTy::I8) => { + // Unsafe because of the call to native code. + // Because this is calling a C function it is not necessarily sound, + // but there is no way around this and we've checked as much as we can. + let x = unsafe { ffi::call::(ptr, libffi_args.as_slice()) }; + Scalar::from_i8(x) + } + ty::Int(IntTy::I16) => { + let x = unsafe { ffi::call::(ptr, libffi_args.as_slice()) }; + Scalar::from_i16(x) + } + ty::Int(IntTy::I32) => { + let x = unsafe { ffi::call::(ptr, libffi_args.as_slice()) }; + Scalar::from_i32(x) + } + ty::Int(IntTy::I64) => { + let x = unsafe { ffi::call::(ptr, libffi_args.as_slice()) }; + Scalar::from_i64(x) + } + ty::Int(IntTy::Isize) => { + let x = unsafe { ffi::call::(ptr, libffi_args.as_slice()) }; + Scalar::from_target_isize(x.try_into().unwrap(), this) + } + // uints + ty::Uint(UintTy::U8) => { + let x = unsafe { ffi::call::(ptr, libffi_args.as_slice()) }; + Scalar::from_u8(x) + } + ty::Uint(UintTy::U16) => { + let x = unsafe { ffi::call::(ptr, libffi_args.as_slice()) }; + Scalar::from_u16(x) + } + ty::Uint(UintTy::U32) => { + let x = unsafe { ffi::call::(ptr, libffi_args.as_slice()) }; + Scalar::from_u32(x) + } + ty::Uint(UintTy::U64) => { + let x = unsafe { ffi::call::(ptr, libffi_args.as_slice()) }; + Scalar::from_u64(x) + } + ty::Uint(UintTy::Usize) => { + let x = unsafe { ffi::call::(ptr, libffi_args.as_slice()) }; + Scalar::from_target_usize(x.try_into().unwrap(), this) + } + // Functions with no declared return type (i.e., the default return) + // have the output_type `Tuple([])`. + ty::Tuple(t_list) if t_list.len() == 0 => { + unsafe { ffi::call::<()>(ptr, libffi_args.as_slice()) }; + return Ok(ImmTy::uninit(dest.layout)); + } + _ => throw_unsup_format!("unsupported return type for native call: {:?}", link_name), + }; + Ok(ImmTy::from_scalar(scalar, dest.layout)) + } + + /// Get the pointer to the function of the specified name in the shared object file, + /// if it exists. The function must be in the shared object file specified: we do *not* + /// return pointers to functions in dependencies of the library. + fn get_func_ptr_explicitly_from_lib(&mut self, link_name: Symbol) -> Option { + let this = self.eval_context_mut(); + // Try getting the function from the shared library. + // On windows `_lib_path` will be unused, hence the name starting with `_`. + let (lib, _lib_path) = this.machine.native_lib.as_ref().unwrap(); + let func: libloading::Symbol<'_, unsafe extern "C" fn()> = unsafe { + match lib.get(link_name.as_str().as_bytes()) { + Ok(x) => x, + Err(_) => { + return None; + } + } + }; + + // FIXME: this is a hack! + // The `libloading` crate will automatically load system libraries like `libc`. + // On linux `libloading` is based on `dlsym`: https://docs.rs/libloading/0.7.3/src/libloading/os/unix/mod.rs.html#202 + // and `dlsym`(https://linux.die.net/man/3/dlsym) looks through the dependency tree of the + // library if it can't find the symbol in the library itself. + // So, in order to check if the function was actually found in the specified + // `machine.external_so_lib` we need to check its `dli_fname` and compare it to + // the specified SO file path. + // This code is a reimplementation of the mechanism for getting `dli_fname` in `libloading`, + // from: https://docs.rs/libloading/0.7.3/src/libloading/os/unix/mod.rs.html#411 + // using the `libc` crate where this interface is public. + let mut info = std::mem::MaybeUninit::::uninit(); + unsafe { + if libc::dladdr(*func.deref() as *const _, info.as_mut_ptr()) != 0 { + if std::ffi::CStr::from_ptr(info.assume_init().dli_fname).to_str().unwrap() + != _lib_path.to_str().unwrap() + { + return None; + } + } + } + // Return a pointer to the function. + Some(CodePtr(*func.deref() as *mut _)) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { + /// Call the native host function, with supplied arguments. + /// Needs to convert all the arguments from their Miri representations to + /// a native form (through `libffi` call). + /// Then, convert the return value from the native form into something that + /// can be stored in Miri's internal memory. + fn call_native_fn( + &mut self, + link_name: Symbol, + dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx, Provenance>], + ) -> InterpResult<'tcx, bool> { + let this = self.eval_context_mut(); + // Get the pointer to the function in the shared object file if it exists. + let code_ptr = match this.get_func_ptr_explicitly_from_lib(link_name) { + Some(ptr) => ptr, + None => { + // Shared object file does not export this function -- try the shims next. + return Ok(false); + } + }; + + // Get the function arguments, and convert them to `libffi`-compatible form. + let mut libffi_args = Vec::::with_capacity(args.len()); + for arg in args.iter() { + if !matches!(arg.layout.abi, Abi::Scalar(_)) { + throw_unsup_format!("only scalar argument types are support for native calls") + } + libffi_args.push(imm_to_carg(this.read_immediate(arg)?, this)?); + } + + // Convert them to `libffi::high::Arg` type. + let libffi_args = libffi_args + .iter() + .map(|arg| arg.arg_downcast()) + .collect::>>(); + + // Call the function and store output, depending on return type in the function signature. + let ret = this.call_native_with_args(link_name, dest, code_ptr, libffi_args)?; + this.write_immediate(*ret, dest)?; + Ok(true) + } +} + +#[derive(Debug, Clone)] +/// Enum of supported arguments to external C functions. +// We introduce this enum instead of just calling `ffi::arg` and storing a list +// of `libffi::high::Arg` directly, because the `libffi::high::Arg` just wraps a reference +// to the value it represents: https://docs.rs/libffi/latest/libffi/high/call/struct.Arg.html +// and we need to store a copy of the value, and pass a reference to this copy to C instead. +enum CArg { + /// 8-bit signed integer. + Int8(i8), + /// 16-bit signed integer. + Int16(i16), + /// 32-bit signed integer. + Int32(i32), + /// 64-bit signed integer. + Int64(i64), + /// isize. + ISize(isize), + /// 8-bit unsigned integer. + UInt8(u8), + /// 16-bit unsigned integer. + UInt16(u16), + /// 32-bit unsigned integer. + UInt32(u32), + /// 64-bit unsigned integer. + UInt64(u64), + /// usize. + USize(usize), +} + +impl<'a> CArg { + /// Convert a `CArg` to a `libffi` argument type. + fn arg_downcast(&'a self) -> libffi::high::Arg<'a> { + match self { + CArg::Int8(i) => ffi::arg(i), + CArg::Int16(i) => ffi::arg(i), + CArg::Int32(i) => ffi::arg(i), + CArg::Int64(i) => ffi::arg(i), + CArg::ISize(i) => ffi::arg(i), + CArg::UInt8(i) => ffi::arg(i), + CArg::UInt16(i) => ffi::arg(i), + CArg::UInt32(i) => ffi::arg(i), + CArg::UInt64(i) => ffi::arg(i), + CArg::USize(i) => ffi::arg(i), + } + } +} + +/// Extract the scalar value from the result of reading a scalar from the machine, +/// and convert it to a `CArg`. +fn imm_to_carg<'tcx>( + v: ImmTy<'tcx, Provenance>, + cx: &impl HasDataLayout, +) -> InterpResult<'tcx, CArg> { + Ok(match v.layout.ty.kind() { + // If the primitive provided can be converted to a type matching the type pattern + // then create a `CArg` of this primitive value with the corresponding `CArg` constructor. + // the ints + ty::Int(IntTy::I8) => CArg::Int8(v.to_scalar().to_i8()?), + ty::Int(IntTy::I16) => CArg::Int16(v.to_scalar().to_i16()?), + ty::Int(IntTy::I32) => CArg::Int32(v.to_scalar().to_i32()?), + ty::Int(IntTy::I64) => CArg::Int64(v.to_scalar().to_i64()?), + ty::Int(IntTy::Isize) => + CArg::ISize(v.to_scalar().to_target_isize(cx)?.try_into().unwrap()), + // the uints + ty::Uint(UintTy::U8) => CArg::UInt8(v.to_scalar().to_u8()?), + ty::Uint(UintTy::U16) => CArg::UInt16(v.to_scalar().to_u16()?), + ty::Uint(UintTy::U32) => CArg::UInt32(v.to_scalar().to_u32()?), + ty::Uint(UintTy::U64) => CArg::UInt64(v.to_scalar().to_u64()?), + ty::Uint(UintTy::Usize) => + CArg::USize(v.to_scalar().to_target_usize(cx)?.try_into().unwrap()), + _ => throw_unsup_format!("unsupported argument type for native call: {}", v.layout.ty), + }) +} diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs index 9082d13da8404..6fcfb69391536 100644 --- a/src/tools/miri/src/shims/unix/env.rs +++ b/src/tools/miri/src/shims/unix/env.rs @@ -228,7 +228,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`getcwd`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; return Ok(Pointer::null()); } @@ -241,7 +241,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let erange = this.eval_libc("ERANGE"); this.set_last_error(erange)?; } - Err(e) => this.set_last_error_from_io_error(e.kind())?, + Err(e) => this.set_last_error_from_io_error(e)?, } Ok(Pointer::null()) @@ -255,7 +255,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`chdir`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; return Ok(-1); } @@ -263,7 +263,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { match env::set_current_dir(path) { Ok(()) => Ok(0), Err(e) => { - this.set_last_error_from_io_error(e.kind())?; + this.set_last_error_from_io_error(e)?; Ok(-1) } } diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index e536b78d1c0bc..a53cd607ef063 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -312,7 +312,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fcntl`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; return Ok(-1); } @@ -394,7 +394,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(read_bytes) } Err(e) => { - this.set_last_error_from_io_error(e.kind())?; + this.set_last_error_from_io_error(e)?; Ok(-1) } } diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 595cf64a4e4b4..08f64e499b558 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -310,7 +310,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_null(dest)?; } Some(len) => { - let res = this.realloc(ptr, len, MiriMemoryKind::C)?; + let res = this.realloc(ptr, len)?; this.write_pointer(res, dest)?; } } @@ -378,8 +378,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { .builtin_deref(true) .ok_or_else(|| err_ub_format!( "wrong signature used for `pthread_key_create`: first argument must be a raw pointer." - ))? - .ty; + ))?; let key_layout = this.layout_of(key_type)?; // Create key and write it into the memory where `key_ptr` wants it. diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 058747916c0ac..eb241556a5691 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -137,37 +137,28 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx &mut self, file_type: std::io::Result, ) -> InterpResult<'tcx, i32> { + #[cfg(unix)] + use std::os::unix::fs::FileTypeExt; + let this = self.eval_context_mut(); match file_type { Ok(file_type) => { - if file_type.is_dir() { - Ok(this.eval_libc("DT_DIR").to_u8()?.into()) - } else if file_type.is_file() { - Ok(this.eval_libc("DT_REG").to_u8()?.into()) - } else if file_type.is_symlink() { - Ok(this.eval_libc("DT_LNK").to_u8()?.into()) - } else { + match () { + _ if file_type.is_dir() => Ok(this.eval_libc("DT_DIR").to_u8()?.into()), + _ if file_type.is_file() => Ok(this.eval_libc("DT_REG").to_u8()?.into()), + _ if file_type.is_symlink() => Ok(this.eval_libc("DT_LNK").to_u8()?.into()), // Certain file types are only supported when the host is a Unix system. - // (i.e. devices and sockets) If it is, check those cases, if not, fall back to - // DT_UNKNOWN sooner. - #[cfg(unix)] - { - use std::os::unix::fs::FileTypeExt; - if file_type.is_block_device() { - Ok(this.eval_libc("DT_BLK").to_u8()?.into()) - } else if file_type.is_char_device() { - Ok(this.eval_libc("DT_CHR").to_u8()?.into()) - } else if file_type.is_fifo() { - Ok(this.eval_libc("DT_FIFO").to_u8()?.into()) - } else if file_type.is_socket() { - Ok(this.eval_libc("DT_SOCK").to_u8()?.into()) - } else { - Ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into()) - } - } - #[cfg(not(unix))] - Ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into()) + _ if file_type.is_block_device() => + Ok(this.eval_libc("DT_BLK").to_u8()?.into()), + #[cfg(unix)] + _ if file_type.is_char_device() => Ok(this.eval_libc("DT_CHR").to_u8()?.into()), + #[cfg(unix)] + _ if file_type.is_fifo() => Ok(this.eval_libc("DT_FIFO").to_u8()?.into()), + #[cfg(unix)] + _ if file_type.is_socket() => Ok(this.eval_libc("DT_SOCK").to_u8()?.into()), + // Fallback + _ => Ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into()), } } Err(e) => @@ -387,7 +378,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`open`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; return Ok(-1); } @@ -443,7 +434,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`unlink`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; return Ok(-1); } @@ -474,7 +465,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`symlink`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; return Ok(-1); } @@ -775,7 +766,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`rename`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; return Ok(-1); } @@ -803,7 +794,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`mkdir`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; return Ok(-1); } @@ -831,7 +822,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`rmdir`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; return Ok(-1); } @@ -868,7 +859,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(Scalar::from_target_usize(id, this)) } Err(e) => { - this.set_last_error_from_io_error(e.kind())?; + this.set_last_error_from_io_error(e)?; Ok(Scalar::null_ptr(this)) } } @@ -956,7 +947,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { None } Some(Err(e)) => { - this.set_last_error_from_io_error(e.kind())?; + this.set_last_error_from_io_error(e)?; None } }; @@ -1308,13 +1299,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(path_bytes.len().try_into().unwrap()) } Err(e) => { - this.set_last_error_from_io_error(e.kind())?; + this.set_last_error_from_io_error(e)?; Ok(-1) } } } - #[cfg_attr(not(unix), allow(unused))] fn isatty( &mut self, miri_fd: &OpTy<'tcx, Provenance>, @@ -1392,7 +1382,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(Scalar::from_maybe_pointer(dest, this)) } Err(e) => { - this.set_last_error_from_io_error(e.kind())?; + this.set_last_error_from_io_error(e)?; Ok(Scalar::from_target_usize(0, this)) } } @@ -1467,8 +1457,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { #[cfg(unix)] { use std::os::unix::fs::OpenOptionsExt; - fopts.mode(0o600); // Do not allow others to read or modify this file. + fopts.mode(0o600); fopts.custom_flags(libc::O_EXCL); } #[cfg(windows)] @@ -1513,7 +1503,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { _ => { // "On error, -1 is returned, and errno is set to // indicate the error" - this.set_last_error_from_io_error(e.kind())?; + this.set_last_error_from_io_error(e)?; return Ok(-1); } }, @@ -1592,7 +1582,7 @@ impl FileMetadata { let metadata = match metadata { Ok(metadata) => metadata, Err(e) => { - ecx.set_last_error_from_io_error(e.kind())?; + ecx.set_last_error_from_io_error(e)?; return Ok(None); } }; diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index ecf82f26a5528..7cd749a41072e 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -117,6 +117,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap). id if id == sys_getrandom => { + // Used by getrandom 0.1 // The first argument is the syscall id, so skip over it. if args.len() < 4 { throw_ub_format!( @@ -124,7 +125,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { args.len() ); } - getrandom(this, &args[1], &args[2], &args[3], dest)?; + + let ptr = this.read_pointer(&args[1])?; + let len = this.read_target_usize(&args[2])?; + // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, + // neither of which have any effect on our current PRNG. + // See for a discussion of argument sizes. + let _flags = this.read_scalar(&args[3])?.to_i32(); + + this.gen_random(ptr, len)?; + this.write_scalar(Scalar::from_target_usize(len, this), dest)?; } // `futex` is used by some synchronization primitives. id if id == sys_futex => { @@ -196,24 +206,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { Ok(EmulateItemResult::NeedsJumping) } } - -// Shims the linux `getrandom` syscall. -fn getrandom<'tcx>( - this: &mut MiriInterpCx<'_, 'tcx>, - ptr: &OpTy<'tcx, Provenance>, - len: &OpTy<'tcx, Provenance>, - flags: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, -) -> InterpResult<'tcx> { - let ptr = this.read_pointer(ptr)?; - let len = this.read_target_usize(len)?; - - // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, - // neither of which have any effect on our current PRNG. - // See for a discussion of argument sizes. - let _flags = this.read_scalar(flags)?.to_i32(); - - this.gen_random(ptr, len)?; - this.write_scalar(Scalar::from_target_usize(len, this), dest)?; - Ok(()) -} diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs index f52dc23656db6..0254735ac138c 100644 --- a/src/tools/miri/src/shims/unix/mem.rs +++ b/src/tools/miri/src/shims/unix/mem.rs @@ -42,9 +42,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let map_shared = this.eval_libc_i32("MAP_SHARED"); let map_fixed = this.eval_libc_i32("MAP_FIXED"); - // This is a horrible hack, but on MacOS the guard page mechanism uses mmap + // This is a horrible hack, but on MacOS and Solaris the guard page mechanism uses mmap // in a way we do not support. We just give it the return value it expects. - if this.frame_in_std() && this.tcx.sess.target.os == "macos" && (flags & map_fixed) != 0 { + if this.frame_in_std() + && matches!(&*this.tcx.sess.target.os, "macos" | "solaris") + && (flags & map_fixed) != 0 + { return Ok(Scalar::from_maybe_pointer(Pointer::from_addr_invalid(addr), this)); } diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index c01ae0ecb908b..c216d8afd7733 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -2,7 +2,6 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use crate::*; -use shims::EmulateItemResult; pub fn is_dyn_sym(_name: &str) -> bool { false @@ -26,6 +25,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } + "stack_getbounds" => { + let [stack] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let stack = this.deref_pointer_as(stack, this.libc_ty_layout("stack_t"))?; + + this.write_int_fields_named( + &[ + ("ss_sp", this.machine.stack_addr.into()), + ("ss_size", this.machine.stack_size.into()), + // field set to 0 means not in an alternate signal stack + // https://docs.oracle.com/cd/E86824_01/html/E54766/stack-getbounds-3c.html + ("ss_flags", 0), + ], + &stack, + )?; + + this.write_null(dest)?; + } + _ => return Ok(EmulateItemResult::NotSupported), } Ok(EmulateItemResult::NeedsJumping) diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs index b3bc5d4d85235..0e52959b762e6 100644 --- a/src/tools/miri/src/shims/windows/env.rs +++ b/src/tools/miri/src/shims/windows/env.rs @@ -153,7 +153,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`GetCurrentDirectoryW`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; return Ok(Scalar::from_u32(0)); } @@ -166,7 +166,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_path_to_wide_str(&cwd, buf, size)?, ))); } - Err(e) => this.set_last_error_from_io_error(e.kind())?, + Err(e) => this.set_last_error_from_io_error(e)?, } Ok(Scalar::from_u32(0)) } @@ -185,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`SetCurrentDirectoryW`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?; return Ok(this.eval_windows("c", "FALSE")); } @@ -193,7 +193,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { match env::set_current_dir(path) { Ok(()) => Ok(this.eval_windows("c", "TRUE")), Err(e) => { - this.set_last_error_from_io_error(e.kind())?; + this.set_last_error_from_io_error(e)?; Ok(this.eval_windows("c", "FALSE")) } } diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index dba5b7a906f91..086abf19c5cff 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -5,10 +5,9 @@ use std::path::{self, Path, PathBuf}; use std::str; use rustc_span::Symbol; -use rustc_target::abi::Size; +use rustc_target::abi::{Align, Size}; use rustc_target::spec::abi::Abi; -use crate::shims::alloc::EvalContextExt as _; use crate::shims::os_str::bytes_to_os_str; use crate::shims::windows::*; use crate::*; @@ -225,7 +224,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let filename = this.read_path_from_wide_str(filename)?; let result = match win_absolute(&filename)? { Err(err) => { - this.set_last_error_from_io_error(err.kind())?; + this.set_last_error_from_io_error(err)?; Scalar::from_u32(0) // return zero upon failure } Ok(abs_filename) => { @@ -248,8 +247,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let size = this.read_target_usize(size)?; let heap_zero_memory = 0x00000008; // HEAP_ZERO_MEMORY let zero_init = (flags & heap_zero_memory) == heap_zero_memory; - let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap)?; - this.write_pointer(res, dest)?; + // Alignment is twice the pointer size. + // Source: + let align = this.tcx.pointer_size().bytes().strict_mul(2); + let ptr = this.allocate_ptr( + Size::from_bytes(size), + Align::from_bytes(align).unwrap(), + MiriMemoryKind::WinHeap.into(), + )?; + if zero_init { + this.write_bytes_ptr( + ptr.into(), + iter::repeat(0u8).take(usize::try_from(size).unwrap()), + )?; + } + this.write_pointer(ptr, dest)?; } "HeapFree" => { let [handle, flags, ptr] = @@ -257,23 +269,41 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.read_target_isize(handle)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_pointer(ptr)?; - this.free(ptr, MiriMemoryKind::WinHeap)?; + // "This pointer can be NULL." It doesn't say what happens then, but presumably nothing. + // (https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapfree) + if !this.ptr_is_null(ptr)? { + this.deallocate_ptr(ptr, None, MiriMemoryKind::WinHeap.into())?; + } this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - let [handle, flags, ptr, size] = + let [handle, flags, old_ptr, size] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_target_isize(handle)?; this.read_scalar(flags)?.to_u32()?; - let ptr = this.read_pointer(ptr)?; + let old_ptr = this.read_pointer(old_ptr)?; let size = this.read_target_usize(size)?; - let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?; - this.write_pointer(res, dest)?; + let align = this.tcx.pointer_size().bytes().strict_mul(2); // same as above + // The docs say that `old_ptr` must come from an earlier HeapAlloc or HeapReAlloc, + // so unlike C `realloc` we do *not* allow a NULL here. + // (https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heaprealloc) + let new_ptr = this.reallocate_ptr( + old_ptr, + None, + Size::from_bytes(size), + Align::from_bytes(align).unwrap(), + MiriMemoryKind::WinHeap.into(), + )?; + this.write_pointer(new_ptr, dest)?; } "LocalFree" => { let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let ptr = this.read_pointer(ptr)?; - this.free(ptr, MiriMemoryKind::WinLocal)?; + // "If the hMem parameter is NULL, LocalFree ignores the parameter and returns NULL." + // (https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localfree) + if !this.ptr_is_null(ptr)? { + this.deallocate_ptr(ptr, None, MiriMemoryKind::WinLocal.into())?; + } this.write_null(dest)?; } @@ -513,6 +543,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { throw_machine_stop!(TerminationInfo::Exit { code: code.into(), leak_check: false }); } "SystemFunction036" => { + // used by getrandom 0.1 // This is really 'RtlGenRandom'. let [ptr, len] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; @@ -522,6 +553,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_scalar(Scalar::from_bool(true), dest)?; } "ProcessPrng" => { + // used by `std` let [ptr, len] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let ptr = this.read_pointer(ptr)?; @@ -530,6 +562,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_scalar(Scalar::from_i32(1), dest)?; } "BCryptGenRandom" => { + // used by getrandom 0.2 let [algorithm, ptr, len, flags] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let algorithm = this.read_scalar(algorithm)?; diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs index 783be802bb73b..bbde5b49588c2 100644 --- a/src/tools/miri/src/shims/x86/avx2.rs +++ b/src/tools/miri/src/shims/x86/avx2.rs @@ -1,5 +1,5 @@ -use crate::rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::mir; +use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::Ty; use rustc_span::Symbol; use rustc_target::spec::abi::Abi; diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py index 2639d29b73de6..83f3e4c919b9a 100755 --- a/src/tools/miri/test-cargo-miri/run-test.py +++ b/src/tools/miri/test-cargo-miri/run-test.py @@ -10,6 +10,7 @@ import re import subprocess import sys +import argparse CGREEN = '\33[32m' CBOLD = '\33[1m' @@ -25,8 +26,8 @@ def cargo_miri(cmd, quiet = True): args = ["cargo", "miri", cmd] + CARGO_EXTRA_FLAGS if quiet: args += ["-q"] - if 'MIRI_TEST_TARGET' in os.environ: - args += ["--target", os.environ['MIRI_TEST_TARGET']] + if ARGS.target: + args += ["--target", ARGS.target] return args def normalize_stdout(str): @@ -35,7 +36,7 @@ def normalize_stdout(str): return str def check_output(actual, path, name): - if os.environ.get("RUSTC_BLESS", "0") != "0": + if ARGS.bless: # Write the output only if bless is set open(path, mode='w').write(actual) return True @@ -133,7 +134,7 @@ def test_cargo_miri_run(): def test_cargo_miri_test(): # rustdoc is not run on foreign targets - is_foreign = 'MIRI_TEST_TARGET' in os.environ + is_foreign = ARGS.target is not None default_ref = "test.cross-target.stdout.ref" if is_foreign else "test.default.stdout.ref" filter_ref = "test.filter.cross-target.stdout.ref" if is_foreign else "test.filter.stdout.ref" @@ -182,16 +183,22 @@ def test_cargo_miri_test(): env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, ) +args_parser = argparse.ArgumentParser(description='`cargo miri` testing') +args_parser.add_argument('--target', help='the target to test') +args_parser.add_argument('--bless', help='bless the reference files', action='store_true') +ARGS = args_parser.parse_args() + os.chdir(os.path.dirname(os.path.realpath(__file__))) os.environ["CARGO_TARGET_DIR"] = "target" # this affects the location of the target directory that we need to check os.environ["RUST_TEST_NOCAPTURE"] = "0" # this affects test output, so make sure it is not set os.environ["RUST_TEST_THREADS"] = "1" # avoid non-deterministic output due to concurrent test runs -target_str = " for target {}".format(os.environ['MIRI_TEST_TARGET']) if 'MIRI_TEST_TARGET' in os.environ else "" +target_str = " for target {}".format(ARGS.target) if ARGS.target else "" print(CGREEN + CBOLD + "## Running `cargo miri` tests{}".format(target_str) + CEND) test_cargo_miri_run() test_cargo_miri_test() + # Ensure we did not create anything outside the expected target dir. for target_dir in ["target", "custom-run", "custom-test", "config-cli"]: if os.listdir(target_dir) != ["miri"]: diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock index 3dd5eb9b91c55..c73d13a4620c2 100644 --- a/src/tools/miri/test_dependencies/Cargo.lock +++ b/src/tools/miri/test_dependencies/Cargo.lock @@ -17,12 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - [[package]] name = "backtrace" version = "0.3.71" @@ -50,12 +44,6 @@ version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" -[[package]] -name = "bytes" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" - [[package]] name = "cc" version = "1.0.96" @@ -141,16 +129,6 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.4.21" @@ -192,7 +170,6 @@ dependencies = [ "libc", "num_cpus", "page_size", - "rand", "tempfile", "tokio", "windows-sys 0.52.0", @@ -233,41 +210,12 @@ dependencies = [ "winapi", ] -[[package]] -name = "parking_lot" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.5", -] - [[package]] name = "pin-project-lite" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - [[package]] name = "proc-macro2" version = "1.0.81" @@ -286,45 +234,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.14", -] - -[[package]] -name = "redox_syscall" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" -dependencies = [ - "bitflags", -] - [[package]] name = "rustc-demangle" version = "0.1.23" @@ -344,27 +253,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - [[package]] name = "socket2" version = "0.5.7" @@ -405,13 +293,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", - "bytes", "libc", "mio", "num_cpus", - "parking_lot", "pin-project-lite", - "signal-hook-registry", "socket2", "tokio-macros", "windows-sys 0.48.0", diff --git a/src/tools/miri/test_dependencies/Cargo.toml b/src/tools/miri/test_dependencies/Cargo.toml index 9f28e4d169f4a..1894f53ce49c0 100644 --- a/src/tools/miri/test_dependencies/Cargo.toml +++ b/src/tools/miri/test_dependencies/Cargo.toml @@ -15,11 +15,10 @@ tempfile = "3" getrandom_01 = { package = "getrandom", version = "0.1" } getrandom_02 = { package = "getrandom", version = "0.2", features = ["js"] } -rand = { version = "0.8", features = ["small_rng"] } [target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies] page_size = "0.6" -tokio = { version = "1.24", features = ["full"] } +tokio = { version = "1.24", features = ["macros", "rt-multi-thread", "time", "net"] } [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.52", features = [ "Win32_Foundation", "Win32_System_Threading" ] } diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_cond_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs similarity index 93% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_cond_double_destroy.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs index 94ca3496ed948..f22f17be0df56 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_cond_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows /// Test that destroying a pthread_cond twice fails, even without a check for number validity diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_cond_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_cond_double_destroy.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_condattr_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs similarity index 92% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_condattr_double_destroy.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs index b5427d55eb07a..d0ccab4de5b58 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_condattr_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows //@ignore-target-apple: Our macOS condattr don't have any fields so we do not notice this. /// Test that destroying a pthread_condattr twice fails, even without a check for number validity diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_condattr_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_condattr_double_destroy.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.rs index 7e6f490bb3dd4..9cd0a35d36e94 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows //@error-in-other-file: the main thread terminated without waiting for all remaining threads // Check that we terminate the program when the main thread terminates. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs index e1d3704af7c0b..96dd99e884428 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows //! The thread function must have exactly one argument. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs index 7408634db528f..d8fbc68d344cd 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows //! The thread function must have exactly one argument. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.rs index 0b810dc8c7212..e89d7a9f02b92 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows // Joining a detached thread is undefined behavior. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.rs index 04ca4bbb3f611..cbad743ca5633 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows // Joining an already joined thread is undefined behavior. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.rs index 7576518216372..002498e6c8263 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows // Joining the main thread is undefined behavior. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.rs index 966f416eeac7e..f5b687a623f73 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows // Joining the same thread from multiple threads is undefined behavior. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs index 0c25c690f3721..4bc1c82a254c5 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows // We are making scheduler assumptions here. //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_NULL_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs similarity index 90% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_NULL_deadlock.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs index 8b2510733831f..0a494c53b4b5c 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_NULL_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows // // Check that if we pass NULL attribute, then we get the default mutex type. diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs similarity index 93% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs index 60d56d41fd986..0328115c63759 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows //@error-in-other-file: deadlock use std::cell::UnsafeCell; diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_default_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs similarity index 91% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_default_deadlock.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs index f443768819f96..1038b8988f99f 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_default_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows // // Check that if we do not set the mutex type, it is the default. diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_default_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_default_deadlock.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_destroy_locked.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.rs similarity index 92% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_destroy_locked.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.rs index ec3965c7574eb..e474712cfd994 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_destroy_locked.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows fn main() { unsafe { diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_destroy_locked.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_destroy_locked.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs similarity index 93% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_double_destroy.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs index 622c3eaeae30d..46f0c5f8d72ee 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows /// Test that destroying a pthread_mutex twice fails, even without a check for number validity diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_double_destroy.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs similarity index 92% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_deadlock.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs index 5ea09fa5aac3d..f311934e28bb3 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows fn main() { unsafe { diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_deadlock.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.rs similarity index 92% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.rs index 8ce7542edb87f..2b5886dc16375 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows fn main() { unsafe { diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_wrong_owner.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.rs similarity index 93% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_wrong_owner.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.rs index b56775252e4b4..686a394f7cb9b 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_wrong_owner.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows use std::cell::UnsafeCell; use std::sync::Arc; diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_wrong_owner.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutexattr_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs similarity index 91% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutexattr_double_destroy.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs index 474a277516d94..51f00d62b75b5 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutexattr_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows /// Test that destroying a pthread_mutexattr twice fails, even without a check for number validity diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutexattr_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutexattr_double_destroy.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.rs similarity index 83% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.rs index 603580ff58abd..fa4575bc1d4d1 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.rs similarity index 83% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.rs index ae44f22d146ca..e734a62bca8db 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs similarity index 89% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_double_destroy.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs index 800986f7506c0..e96f7fc680382 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_double_destroy.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows /// Test that destroying a pthread_rwlock twice fails, even without a check for number validity diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_double_destroy.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.rs similarity index 82% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.rs index 782c95b6d2e3c..dffeee2b794ec 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.rs similarity index 93% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.rs index 1b498ad8fcdb4..328372b22ef93 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows use std::cell::UnsafeCell; use std::sync::Arc; diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.rs similarity index 78% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.rs index 05f7e7a06c57f..ced6b7a4f613c 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs similarity index 93% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs index 0f02c3231a688..4174751926d85 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows //@error-in-other-file: deadlock use std::cell::UnsafeCell; diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.rs similarity index 82% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.rs index 538f14ef89f20..099b8dcd106ac 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs similarity index 93% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs index 10be5b3375230..43b3ab09bb237 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows //@error-in-other-file: deadlock use std::cell::UnsafeCell; diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.rs similarity index 82% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.rs index 2c963d36510e6..2704ff154413c 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.rs similarity index 93% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.rs index dd099474d8fed..9a2cd09f083e7 100644 --- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows use std::cell::UnsafeCell; use std::sync::Arc; diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.rs b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs similarity index 90% rename from src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.rs rename to src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs index 2b9e7a34d6543..a1895feb957bc 100644 --- a/src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.rs +++ b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No libc env support on Windows use std::env; use std::thread; diff --git a/src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.stderr b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.stderr rename to src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/fs/close_stdout.rs b/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs similarity index 82% rename from src/tools/miri/tests/fail-dep/shims/fs/close_stdout.rs rename to src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs index 09da8509af412..42b7e2b7838cb 100644 --- a/src/tools/miri/tests/fail-dep/shims/fs/close_stdout.rs +++ b/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No libc IO on Windows //@compile-flags: -Zmiri-disable-isolation // FIXME: standard handles cannot be closed (https://github.com/rust-lang/rust/issues/40032) diff --git a/src/tools/miri/tests/fail-dep/shims/fs/close_stdout.stderr b/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/fs/close_stdout.stderr rename to src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/fs/isolated_stdin.rs b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs similarity index 83% rename from src/tools/miri/tests/fail-dep/shims/fs/isolated_stdin.rs rename to src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs index a45f805696d49..3c62015a051ad 100644 --- a/src/tools/miri/tests/fail-dep/shims/fs/isolated_stdin.rs +++ b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No libc IO on Windows fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; diff --git a/src/tools/miri/tests/fail-dep/shims/fs/isolated_stdin.stderr b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/fs/isolated_stdin.stderr rename to src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/fs/mkstemp_immutable_arg.rs b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs similarity index 86% rename from src/tools/miri/tests/fail-dep/shims/fs/mkstemp_immutable_arg.rs rename to src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs index ba9f404d7c9ac..6d951a3a7b387 100644 --- a/src/tools/miri/tests/fail-dep/shims/fs/mkstemp_immutable_arg.rs +++ b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No mkstemp on Windows //@compile-flags: -Zmiri-disable-isolation fn main() { diff --git a/src/tools/miri/tests/fail-dep/shims/fs/mkstemp_immutable_arg.stderr b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/fs/mkstemp_immutable_arg.stderr rename to src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/fs/read_from_stdout.rs b/src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.rs similarity index 83% rename from src/tools/miri/tests/fail-dep/shims/fs/read_from_stdout.rs rename to src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.rs index 073fca4712e9a..624f584a0c85e 100644 --- a/src/tools/miri/tests/fail-dep/shims/fs/read_from_stdout.rs +++ b/src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No libc IO on Windows fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; diff --git a/src/tools/miri/tests/fail-dep/shims/fs/read_from_stdout.stderr b/src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/fs/read_from_stdout.stderr rename to src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/fs/unix_open_missing_required_mode.rs b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs similarity index 89% rename from src/tools/miri/tests/fail-dep/shims/fs/unix_open_missing_required_mode.rs rename to src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs index ae231d4be667e..d783967f95968 100644 --- a/src/tools/miri/tests/fail-dep/shims/fs/unix_open_missing_required_mode.rs +++ b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No libc IO on Windows //@compile-flags: -Zmiri-disable-isolation fn main() { diff --git a/src/tools/miri/tests/fail-dep/shims/fs/unix_open_missing_required_mode.stderr b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/fs/unix_open_missing_required_mode.stderr rename to src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/fs/write_to_stdin.rs b/src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.rs similarity index 80% rename from src/tools/miri/tests/fail-dep/shims/fs/write_to_stdin.rs rename to src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.rs index d039ad718d339..683c55e90e182 100644 --- a/src/tools/miri/tests/fail-dep/shims/fs/write_to_stdin.rs +++ b/src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No libc IO on Windows fn main() -> std::io::Result<()> { let bytes = b"hello"; diff --git a/src/tools/miri/tests/fail-dep/shims/fs/write_to_stdin.stderr b/src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/fs/write_to_stdin.stderr rename to src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.stderr diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.rs b/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.rs new file mode 100644 index 0000000000000..3298d61c8e8c4 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.rs @@ -0,0 +1,7 @@ +fn main() { + unsafe { + let ptr = libc::malloc(0); + libc::free(ptr); + libc::free(ptr); //~ERROR: dangling + } +} diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.stderr b/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.stderr new file mode 100644 index 0000000000000..6437c9dbeb44a --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling + --> $DIR/malloc_zero_double_free.rs:LL:CC + | +LL | libc::free(ptr); + | ^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information +help: ALLOC was allocated here: + --> $DIR/malloc_zero_double_free.rs:LL:CC + | +LL | let ptr = libc::malloc(0); + | ^^^^^^^^^^^^^^^ +help: ALLOC was deallocated here: + --> $DIR/malloc_zero_double_free.rs:LL:CC + | +LL | libc::free(ptr); + | ^^^^^^^^^^^^^^^ + = note: BACKTRACE (of the first span): + = note: inside `main` at $DIR/malloc_zero_double_free.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.rs b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.rs new file mode 100644 index 0000000000000..b09a74f41d7dd --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.rs @@ -0,0 +1,5 @@ +fn main() { + unsafe { + let _ptr = libc::malloc(0); //~ERROR: memory leak + } +} diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr new file mode 100644 index 0000000000000..65ce0dcdcddea --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr @@ -0,0 +1,15 @@ +error: memory leaked: ALLOC (C heap, size: 0, align: 1), allocated here: + --> $DIR/malloc_zero_memory_leak.rs:LL:CC + | +LL | let _ptr = libc::malloc(0); + | ^^^^^^^^^^^^^^^ + | + = note: BACKTRACE: + = note: inside `main` at $DIR/malloc_zero_memory_leak.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail-dep/shims/memchr_null.rs b/src/tools/miri/tests/fail-dep/libc/memchr_null.rs similarity index 77% rename from src/tools/miri/tests/fail-dep/shims/memchr_null.rs rename to src/tools/miri/tests/fail-dep/libc/memchr_null.rs index 6bc7af7e6bf77..672cc10cd6304 100644 --- a/src/tools/miri/tests/fail-dep/shims/memchr_null.rs +++ b/src/tools/miri/tests/fail-dep/libc/memchr_null.rs @@ -1,5 +1,3 @@ -//@ignore-target-windows: No libc on Windows - use std::ptr; // null is explicitly called out as UB in the C docs. diff --git a/src/tools/miri/tests/fail-dep/shims/memchr_null.stderr b/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/memchr_null.stderr rename to src/tools/miri/tests/fail-dep/libc/memchr_null.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/memcmp_null.rs b/src/tools/miri/tests/fail-dep/libc/memcmp_null.rs similarity index 78% rename from src/tools/miri/tests/fail-dep/shims/memcmp_null.rs rename to src/tools/miri/tests/fail-dep/libc/memcmp_null.rs index a4e0034c40bdc..066af4a8ae3c9 100644 --- a/src/tools/miri/tests/fail-dep/shims/memcmp_null.rs +++ b/src/tools/miri/tests/fail-dep/libc/memcmp_null.rs @@ -1,5 +1,3 @@ -//@ignore-target-windows: No libc on Windows - use std::ptr; // null is explicitly called out as UB in the C docs. diff --git a/src/tools/miri/tests/fail-dep/shims/memcmp_null.stderr b/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/memcmp_null.stderr rename to src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/memcmp_zero.rs b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.rs similarity index 90% rename from src/tools/miri/tests/fail-dep/shims/memcmp_zero.rs rename to src/tools/miri/tests/fail-dep/libc/memcmp_zero.rs index f2ddc20056327..e28aa26270e49 100644 --- a/src/tools/miri/tests/fail-dep/shims/memcmp_zero.rs +++ b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-permissive-provenance // C says that passing "invalid" pointers is UB for all string functions. diff --git a/src/tools/miri/tests/fail-dep/shims/memcmp_zero.stderr b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/memcmp_zero.stderr rename to src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/memcpy_zero.rs b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.rs similarity index 88% rename from src/tools/miri/tests/fail-dep/shims/memcpy_zero.rs rename to src/tools/miri/tests/fail-dep/libc/memcpy_zero.rs index 5283fea4cb989..b37ed7df74ffa 100644 --- a/src/tools/miri/tests/fail-dep/shims/memcpy_zero.rs +++ b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-permissive-provenance // C's memcpy is 0 bytes is UB for some pointers that are allowed in Rust's `copy_nonoverlapping`. diff --git a/src/tools/miri/tests/fail-dep/shims/memcpy_zero.stderr b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/memcpy_zero.stderr rename to src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/memrchr_null.rs b/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs similarity index 81% rename from src/tools/miri/tests/fail-dep/shims/memrchr_null.rs rename to src/tools/miri/tests/fail-dep/libc/memrchr_null.rs index b6707d558d8f6..f06336b129959 100644 --- a/src/tools/miri/tests/fail-dep/shims/memrchr_null.rs +++ b/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No `memrchr` on Windows //@ignore-target-apple: No `memrchr` on some apple targets use std::ptr; diff --git a/src/tools/miri/tests/fail-dep/shims/memrchr_null.stderr b/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/memrchr_null.stderr rename to src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/mmap_invalid_dealloc.rs b/src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.rs similarity index 90% rename from src/tools/miri/tests/fail-dep/shims/mmap_invalid_dealloc.rs rename to src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.rs index 70f7a6a7cef12..9d55a4935547f 100644 --- a/src/tools/miri/tests/fail-dep/shims/mmap_invalid_dealloc.rs +++ b/src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No mmap on Windows #![feature(rustc_private)] diff --git a/src/tools/miri/tests/fail-dep/shims/mmap_invalid_dealloc.stderr b/src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/mmap_invalid_dealloc.stderr rename to src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/mmap_use_after_munmap.rs b/src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.rs similarity index 90% rename from src/tools/miri/tests/fail-dep/shims/mmap_use_after_munmap.rs rename to src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.rs index c97b013ba5a34..05ac232f5d7b4 100644 --- a/src/tools/miri/tests/fail-dep/shims/mmap_use_after_munmap.rs +++ b/src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No mmap on Windows #![feature(rustc_private)] diff --git a/src/tools/miri/tests/fail-dep/shims/mmap_use_after_munmap.stderr b/src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/mmap_use_after_munmap.stderr rename to src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.stderr diff --git a/src/tools/miri/tests/fail-dep/shims/munmap_partial.rs b/src/tools/miri/tests/fail-dep/libc/munmap_partial.rs similarity index 94% rename from src/tools/miri/tests/fail-dep/shims/munmap_partial.rs rename to src/tools/miri/tests/fail-dep/libc/munmap_partial.rs index d7aef47235f1e..4386dc71af69c 100644 --- a/src/tools/miri/tests/fail-dep/shims/munmap_partial.rs +++ b/src/tools/miri/tests/fail-dep/libc/munmap_partial.rs @@ -1,7 +1,7 @@ //! The man pages for mmap/munmap suggest that it is possible to partly unmap a previously-mapped //! region of address space, but to LLVM that would be partial deallocation, which LLVM does not //! support. So even though the man pages say this sort of use is possible, we must report UB. -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No mmap on Windows //@normalize-stderr-test: "size [0-9]+ and alignment" -> "size SIZE and alignment" fn main() { diff --git a/src/tools/miri/tests/fail-dep/shims/munmap_partial.stderr b/src/tools/miri/tests/fail-dep/libc/munmap_partial.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/shims/munmap_partial.stderr rename to src/tools/miri/tests/fail-dep/libc/munmap_partial.stderr diff --git a/src/tools/miri/tests/fail-dep/realloc-zero.rs b/src/tools/miri/tests/fail-dep/libc/realloc-zero.rs similarity index 81% rename from src/tools/miri/tests/fail-dep/realloc-zero.rs rename to src/tools/miri/tests/fail-dep/libc/realloc-zero.rs index 1482798e90c08..0e210f313569a 100644 --- a/src/tools/miri/tests/fail-dep/realloc-zero.rs +++ b/src/tools/miri/tests/fail-dep/libc/realloc-zero.rs @@ -1,5 +1,3 @@ -//@ignore-target-windows: No libc on Windows - fn main() { unsafe { let p1 = libc::malloc(20); diff --git a/src/tools/miri/tests/fail-dep/realloc-zero.stderr b/src/tools/miri/tests/fail-dep/libc/realloc-zero.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/realloc-zero.stderr rename to src/tools/miri/tests/fail-dep/libc/realloc-zero.stderr diff --git a/src/tools/miri/tests/fail-dep/unsupported_incomplete_function.rs b/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.rs similarity index 87% rename from src/tools/miri/tests/fail-dep/unsupported_incomplete_function.rs rename to src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.rs index 6ef842c9ccb64..cd8422f4afd40 100644 --- a/src/tools/miri/tests/fail-dep/unsupported_incomplete_function.rs +++ b/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.rs @@ -1,6 +1,6 @@ //! `signal()` is special on Linux and macOS that it's only supported within libstd. //! The implementation is not complete enough to permit user code to call it. -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No `libc::signal` on Windows //@normalize-stderr-test: "OS `.*`" -> "$$OS" fn main() { diff --git a/src/tools/miri/tests/fail-dep/unsupported_incomplete_function.stderr b/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.stderr similarity index 100% rename from src/tools/miri/tests/fail-dep/unsupported_incomplete_function.stderr rename to src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.stderr diff --git a/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.rs b/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.rs index 428f371ca51c7..eca6d908b448b 100644 --- a/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.rs +++ b/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.rs @@ -2,7 +2,7 @@ #![feature(custom_mir)] use std::intrinsics::mir::*; -use std::num::NonZeroI32; +use std::num::NonZero; // We define our own option type so that we can control the variant indices. #[allow(unused)] @@ -13,7 +13,7 @@ enum Option { use Option::*; #[custom_mir(dialect = "runtime", phase = "optimized")] -fn set_discriminant(ptr: &mut Option) { +fn set_discriminant(ptr: &mut Option>) { mir! { { // We set the discriminant to `Some`, which is a NOP since this is the niched variant. diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs index 2cf4e04477778..c5900489b4c64 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs @@ -1,7 +1,7 @@ -use std::num::*; +use std::num::NonZero; #[repr(C)] -struct S1(NonZeroI32); +struct S1(NonZero); #[repr(C)] struct S2(i32); @@ -11,6 +11,6 @@ fn callee(_s: S2) {} fn main() { let fnptr: fn(S2) = callee; let fnptr: fn(S1) = unsafe { std::mem::transmute(fnptr) }; - fnptr(S1(NonZeroI32::new(1).unwrap())); + fnptr(S1(NonZero::new(1).unwrap())); //~^ ERROR: calling a function with argument of type S2 passing data of type S1 } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr index eaacc32bf6880..8ec19db813adf 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: calling a function with argument of type S2 passing data of type S1 --> $DIR/abi_mismatch_repr_C.rs:LL:CC | -LL | fnptr(S1(NonZeroI32::new(1).unwrap())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with argument of type S2 passing data of type S1 +LL | fnptr(S1(NonZero::new(1).unwrap())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with argument of type S2 passing data of type S1 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs new file mode 100644 index 0000000000000..57b4fd0dedb7c --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs @@ -0,0 +1,21 @@ +#![feature(strict_provenance)] +use core::ptr; + +fn main() { + unsafe { + let base = ptr::without_provenance::<()>(10); + let unit = &*base; + let p1 = unit as *const (); + + let base = ptr::without_provenance::<()>(11); + let unit = &*base; + let p2 = unit as *const (); + + // Seems to work because they are same pointer + // even though it's dangling. + let _ = p1.byte_offset_from(p1); + + // UB because different pointers. + let _ = p1.byte_offset_from(p2); //~ERROR: different pointers without provenance + } +} diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr new file mode 100644 index 0000000000000..6e9e5633fecc6 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation) + --> $DIR/ptr_offset_from_different_ints.rs:LL:CC + | +LL | let _ = p1.byte_offset_from(p2); + | ^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/ptr_offset_from_different_ints.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs index 7cdc15c609495..9fabdd8e86ba4 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs @@ -2,15 +2,15 @@ #![feature(core_intrinsics, custom_mir)] use std::intrinsics::mir::*; -use std::num::NonZeroU32; +use std::num::NonZero; use std::ptr; -// This function supposedly returns a NonZeroU32, but actually returns something invalid in a way that -// never materializes a bad NonZeroU32 value: we take a pointer to the return place and cast the pointer +// This function supposedly returns a `NonZero`, but actually returns something invalid in a way that +// never materializes a bad `NonZero` value: we take a pointer to the return place and cast the pointer // type. That way we never get an "invalid value constructed" error inside the function, it can // only possibly be detected when the return value is passed to the caller. #[custom_mir(dialect = "runtime", phase = "optimized")] -fn f() -> NonZeroU32 { +fn f() -> NonZero { mir! { { let tmp = ptr::addr_of_mut!(RET); @@ -22,7 +22,7 @@ fn f() -> NonZeroU32 { } fn main() { - let f: fn() -> u32 = unsafe { std::mem::transmute(f as fn() -> NonZeroU32) }; - // There's a NonZeroU32-to-u32 transmute happening here + let f: fn() -> u32 = unsafe { std::mem::transmute(f as fn() -> NonZero) }; + // There's a `NonZero` to `u32` transmute happening here. f(); //~ERROR: expected something greater or equal to 1 } diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs index 3a87bb786776e..7ca26bffc14fd 100644 --- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs +++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs @@ -2,24 +2,24 @@ #![feature(core_intrinsics, custom_mir)] use std::intrinsics::mir::*; -use std::num::NonZeroU32; +use std::num::NonZero; use std::ptr; fn f(c: u32) { println!("{c}"); } -// Call that function in a bad way, with an invalid NonZeroU32, but without -// ever materializing this as a NonZeroU32 value outside the call itself. +// Call that function in a bad way, with an invalid `NonZero`, but without +// ever materializing this as a `NonZero` value outside the call itself. #[custom_mir(dialect = "runtime", phase = "optimized")] -fn call(f: fn(NonZeroU32)) { +fn call(f: fn(NonZero)) { mir! { let _res: (); { let c = 0; let tmp = ptr::addr_of!(c); - let ptr = tmp as *const NonZeroU32; - // The call site now is a NonZeroU32-to-u32 transmute. + let ptr = tmp as *const NonZero; + // The call site now is a `NonZero` to `u32` transmute. Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue()) //~ERROR: expected something greater or equal to 1 } retblock = { @@ -29,6 +29,6 @@ fn call(f: fn(NonZeroU32)) { } fn main() { - let f: fn(NonZeroU32) = unsafe { std::mem::transmute(f as fn(u32)) }; + let f: fn(NonZero) = unsafe { std::mem::transmute(f as fn(u32)) }; call(f); } diff --git a/src/tools/miri/tests/extern-so/fail/function_not_in_so.rs b/src/tools/miri/tests/native-lib/fail/function_not_in_so.rs similarity index 100% rename from src/tools/miri/tests/extern-so/fail/function_not_in_so.rs rename to src/tools/miri/tests/native-lib/fail/function_not_in_so.rs diff --git a/src/tools/miri/tests/extern-so/fail/function_not_in_so.stderr b/src/tools/miri/tests/native-lib/fail/function_not_in_so.stderr similarity index 100% rename from src/tools/miri/tests/extern-so/fail/function_not_in_so.stderr rename to src/tools/miri/tests/native-lib/fail/function_not_in_so.stderr diff --git a/src/tools/miri/tests/extern-so/libtest.map b/src/tools/miri/tests/native-lib/libtest.map similarity index 100% rename from src/tools/miri/tests/extern-so/libtest.map rename to src/tools/miri/tests/native-lib/libtest.map diff --git a/src/tools/miri/tests/extern-so/pass/call_extern_c_fn.rs b/src/tools/miri/tests/native-lib/pass/call_extern_c_fn.rs similarity index 100% rename from src/tools/miri/tests/extern-so/pass/call_extern_c_fn.rs rename to src/tools/miri/tests/native-lib/pass/call_extern_c_fn.rs diff --git a/src/tools/miri/tests/extern-so/pass/call_extern_c_fn.stdout b/src/tools/miri/tests/native-lib/pass/call_extern_c_fn.stdout similarity index 100% rename from src/tools/miri/tests/extern-so/pass/call_extern_c_fn.stdout rename to src/tools/miri/tests/native-lib/pass/call_extern_c_fn.stdout diff --git a/src/tools/miri/tests/extern-so/test.c b/src/tools/miri/tests/native-lib/test.c similarity index 100% rename from src/tools/miri/tests/extern-so/test.c rename to src/tools/miri/tests/native-lib/test.c diff --git a/src/tools/miri/tests/panic/unsupported_syscall.rs b/src/tools/miri/tests/panic/unsupported_syscall.rs index 31d666e1d9d80..30f9da5f80e78 100644 --- a/src/tools/miri/tests/panic/unsupported_syscall.rs +++ b/src/tools/miri/tests/panic/unsupported_syscall.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: no `syscall` on Windows //@ignore-target-apple: `syscall` is not supported on macOS //@compile-flags: -Zmiri-panic-on-unsupported diff --git a/src/tools/miri/tests/pass-dep/calloc.rs b/src/tools/miri/tests/pass-dep/calloc.rs deleted file mode 100644 index 62ab63c5fc788..0000000000000 --- a/src/tools/miri/tests/pass-dep/calloc.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ignore-target-windows: No libc on Windows - -use core::slice; - -fn main() { - unsafe { - let p1 = libc::calloc(0, 0); - assert!(p1.is_null()); - - let p2 = libc::calloc(20, 0); - assert!(p2.is_null()); - - let p3 = libc::calloc(0, 20); - assert!(p3.is_null()); - - let p4 = libc::calloc(4, 8); - assert!(!p4.is_null()); - let slice = slice::from_raw_parts(p4 as *const u8, 4 * 8); - assert_eq!(&slice, &[0_u8; 4 * 8]); - libc::free(p4); - } -} diff --git a/src/tools/miri/tests/pass-dep/shims/env-cleanup-data-race.rs b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs similarity index 93% rename from src/tools/miri/tests/pass-dep/shims/env-cleanup-data-race.rs rename to src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs index 5c29a1b15a792..86a47ba365526 100644 --- a/src/tools/miri/tests/pass-dep/shims/env-cleanup-data-race.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No libc env support on Windows use std::ffi::CStr; use std::thread; diff --git a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs b/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs index f362caa11dc59..d758168c7c30d 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows //@ignore-target-apple: pthread_condattr_setclock is not supported on MacOS. //@compile-flags: -Zmiri-disable-isolation diff --git a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs b/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs index 66c0895a5dab0..f1a3c5dc10d07 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows //@ignore-target-apple: pthread_condattr_setclock is not supported on MacOS. /// Test that conditional variable timeouts are working properly diff --git a/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs b/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs index ae874740f2bc3..0eaab9676429d 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows //! Test that pthread_key destructors are run in the right order. //! Note that these are *not* used by actual `thread_local!` on Linux! Those use //! `thread_local_dtor::register_dtor` from the stdlib instead. In Miri this hits the fallback path diff --git a/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs b/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs index 716119a0fc344..1198168795daf 100644 --- a/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs +++ b/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No `dlsym` on Windows //@compile-flags: -Zmiri-permissive-provenance #[path = "../utils/mod.rs"] diff --git a/src/tools/miri/tests/pass-dep/getrandom.rs b/src/tools/miri/tests/pass-dep/getrandom.rs index c0d9296a9a6d9..53de3af76350c 100644 --- a/src/tools/miri/tests/pass-dep/getrandom.rs +++ b/src/tools/miri/tests/pass-dep/getrandom.rs @@ -1,8 +1,9 @@ // mac-os `getrandom_01` does some pointer shenanigans //@compile-flags: -Zmiri-permissive-provenance +//@revisions: isolation no_isolation +//@[no_isolation]compile-flags: -Zmiri-disable-isolation /// Test direct calls of getrandom 0.1 and 0.2. -/// Make sure they work even with isolation enabled (i.e., we do not hit a file-based fallback path). fn main() { let mut data = vec![0; 16]; getrandom_01::getrandom(&mut data).unwrap(); diff --git a/src/tools/miri/tests/pass-dep/shims/fcntl_f-fullfsync_apple.rs b/src/tools/miri/tests/pass-dep/libc/fcntl_f-fullfsync_apple.rs similarity index 100% rename from src/tools/miri/tests/pass-dep/shims/fcntl_f-fullfsync_apple.rs rename to src/tools/miri/tests/pass-dep/libc/fcntl_f-fullfsync_apple.rs diff --git a/src/tools/miri/tests/pass-dep/shims/fcntl_f-fullfsync_apple.stderr b/src/tools/miri/tests/pass-dep/libc/fcntl_f-fullfsync_apple.stderr similarity index 100% rename from src/tools/miri/tests/pass-dep/shims/fcntl_f-fullfsync_apple.stderr rename to src/tools/miri/tests/pass-dep/libc/fcntl_f-fullfsync_apple.stderr diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-readlink.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-readlink.rs new file mode 100644 index 0000000000000..d72edd7d9e3f2 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-readlink.rs @@ -0,0 +1,51 @@ +// Symlink tests are separate since they don't in general work on a Windows host. +//@ignore-host-windows: creating symlinks requires admin permissions on Windows +//@ignore-target-windows: File handling is not implemented yet +//@compile-flags: -Zmiri-disable-isolation + +use std::ffi::CString; +use std::io::{Error, ErrorKind}; +use std::os::unix::ffi::OsStrExt; + +#[path = "../../utils/mod.rs"] +mod utils; + +fn main() { + let bytes = b"Hello, World!\n"; + let path = utils::prepare_with_content("miri_test_fs_link_target.txt", bytes); + let expected_path = path.as_os_str().as_bytes(); + + let symlink_path = utils::prepare("miri_test_fs_symlink.txt"); + std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); + + // Test that the expected string gets written to a buffer of proper + // length, and that a trailing null byte is not written. + let symlink_c_str = CString::new(symlink_path.as_os_str().as_bytes()).unwrap(); + let symlink_c_ptr = symlink_c_str.as_ptr(); + + // Make the buf one byte larger than it needs to be, + // and check that the last byte is not overwritten. + let mut large_buf = vec![0xFF; expected_path.len() + 1]; + let res = + unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) }; + // Check that the resolved path was properly written into the buf. + assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path); + assert_eq!(large_buf.last(), Some(&0xFF)); + assert_eq!(res, large_buf.len() as isize - 1); + + // Test that the resolved path is truncated if the provided buffer + // is too small. + let mut small_buf = [0u8; 2]; + let res = + unsafe { libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) }; + assert_eq!(small_buf, &expected_path[..small_buf.len()]); + assert_eq!(res, small_buf.len() as isize); + + // Test that we report a proper error for a missing path. + let bad_path = CString::new("MIRI_MISSING_FILE_NAME").unwrap(); + let res = unsafe { + libc::readlink(bad_path.as_ptr(), small_buf.as_mut_ptr().cast(), small_buf.len()) + }; + assert_eq!(res, -1); + assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound); +} diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs similarity index 93% rename from src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs rename to src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs index 5185db0b0e29f..088a632427e70 100644 --- a/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: no libc on Windows +//@ignore-target-windows: File handling is not implemented yet //@compile-flags: -Zmiri-isolation-error=warn-nobacktrace //@normalize-stderr-test: "(stat(x)?)" -> "$$STAT" diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.stderr b/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.stderr similarity index 100% rename from src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.stderr rename to src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.stderr diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs similarity index 78% rename from src/tools/miri/tests/pass-dep/shims/libc-fs.rs rename to src/tools/miri/tests/pass-dep/libc/libc-fs.rs index 0dd849a045dfa..80c9757e9c956 100644 --- a/src/tools/miri/tests/pass-dep/shims/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -1,11 +1,11 @@ -//@ignore-target-windows: no libc on Windows +//@ignore-target-windows: File handling is not implemented yet //@compile-flags: -Zmiri-disable-isolation #![feature(io_error_more)] #![feature(io_error_uncategorized)] use std::ffi::{CStr, CString, OsString}; -use std::fs::{canonicalize, remove_dir_all, remove_file, File}; +use std::fs::{canonicalize, remove_file, File}; use std::io::{Error, ErrorKind, Write}; use std::os::unix::ffi::OsStrExt; use std::os::unix::io::AsRawFd; @@ -21,7 +21,6 @@ fn main() { test_ftruncate::(libc::ftruncate); #[cfg(target_os = "linux")] test_ftruncate::(libc::ftruncate64); - test_readlink(); test_file_open_unix_allow_two_args(); test_file_open_unix_needs_three_args(); test_file_open_unix_extra_third_arg(); @@ -38,33 +37,8 @@ fn main() { test_isatty(); } -/// Prepare: compute filename and make sure the file does not exist. -fn prepare(filename: &str) -> PathBuf { - let path = utils::tmp().join(filename); - // Clean the paths for robustness. - remove_file(&path).ok(); - path -} - -/// Prepare directory: compute directory name and make sure it does not exist. -#[allow(unused)] -fn prepare_dir(dirname: &str) -> PathBuf { - let path = utils::tmp().join(&dirname); - // Clean the directory for robustness. - remove_dir_all(&path).ok(); - path -} - -/// Prepare like above, and also write some initial content to the file. -fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf { - let path = prepare(filename); - let mut file = File::create(&path).unwrap(); - file.write(content).unwrap(); - path -} - fn test_file_open_unix_allow_two_args() { - let path = prepare_with_content("test_file_open_unix_allow_two_args.txt", &[]); + let path = utils::prepare_with_content("test_file_open_unix_allow_two_args.txt", &[]); let mut name = path.into_os_string(); name.push("\0"); @@ -73,7 +47,7 @@ fn test_file_open_unix_allow_two_args() { } fn test_file_open_unix_needs_three_args() { - let path = prepare_with_content("test_file_open_unix_needs_three_args.txt", &[]); + let path = utils::prepare_with_content("test_file_open_unix_needs_three_args.txt", &[]); let mut name = path.into_os_string(); name.push("\0"); @@ -82,7 +56,7 @@ fn test_file_open_unix_needs_three_args() { } fn test_file_open_unix_extra_third_arg() { - let path = prepare_with_content("test_file_open_unix_extra_third_arg.txt", &[]); + let path = utils::prepare_with_content("test_file_open_unix_extra_third_arg.txt", &[]); let mut name = path.into_os_string(); name.push("\0"); @@ -106,49 +80,9 @@ fn test_canonicalize_too_long() { assert!(canonicalize(too_long).is_err()); } -fn test_readlink() { - let bytes = b"Hello, World!\n"; - let path = prepare_with_content("miri_test_fs_link_target.txt", bytes); - let expected_path = path.as_os_str().as_bytes(); - - let symlink_path = prepare("miri_test_fs_symlink.txt"); - std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); - - // Test that the expected string gets written to a buffer of proper - // length, and that a trailing null byte is not written. - let symlink_c_str = CString::new(symlink_path.as_os_str().as_bytes()).unwrap(); - let symlink_c_ptr = symlink_c_str.as_ptr(); - - // Make the buf one byte larger than it needs to be, - // and check that the last byte is not overwritten. - let mut large_buf = vec![0xFF; expected_path.len() + 1]; - let res = - unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) }; - // Check that the resolved path was properly written into the buf. - assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path); - assert_eq!(large_buf.last(), Some(&0xFF)); - assert_eq!(res, large_buf.len() as isize - 1); - - // Test that the resolved path is truncated if the provided buffer - // is too small. - let mut small_buf = [0u8; 2]; - let res = - unsafe { libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) }; - assert_eq!(small_buf, &expected_path[..small_buf.len()]); - assert_eq!(res, small_buf.len() as isize); - - // Test that we report a proper error for a missing path. - let bad_path = CString::new("MIRI_MISSING_FILE_NAME").unwrap(); - let res = unsafe { - libc::readlink(bad_path.as_ptr(), small_buf.as_mut_ptr().cast(), small_buf.len()) - }; - assert_eq!(res, -1); - assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound); -} - fn test_rename() { - let path1 = prepare("miri_test_libc_fs_source.txt"); - let path2 = prepare("miri_test_libc_fs_rename_destination.txt"); + let path1 = utils::prepare("miri_test_libc_fs_source.txt"); + let path2 = utils::prepare("miri_test_libc_fs_rename_destination.txt"); let file = File::create(&path1).unwrap(); drop(file); @@ -178,7 +112,7 @@ fn test_ftruncate>( // https://docs.rs/libc/latest/i686-unknown-linux-gnu/libc/type.off_t.html let bytes = b"hello"; - let path = prepare("miri_test_libc_fs_ftruncate.txt"); + let path = utils::prepare("miri_test_libc_fs_ftruncate.txt"); let mut file = File::create(&path).unwrap(); file.write(bytes).unwrap(); file.sync_all().unwrap(); @@ -209,7 +143,7 @@ fn test_ftruncate>( fn test_o_tmpfile_flag() { use std::fs::{create_dir, OpenOptions}; use std::os::unix::fs::OpenOptionsExt; - let dir_path = prepare_dir("miri_test_fs_dir"); + let dir_path = utils::prepare_dir("miri_test_fs_dir"); create_dir(&dir_path).unwrap(); // test that the `O_TMPFILE` custom flag gracefully errors instead of stopping execution assert_eq!( diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs.stderr b/src/tools/miri/tests/pass-dep/libc/libc-fs.stderr similarity index 100% rename from src/tools/miri/tests/pass-dep/shims/libc-fs.stderr rename to src/tools/miri/tests/pass-dep/libc/libc-fs.stderr diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs.stdout b/src/tools/miri/tests/pass-dep/libc/libc-fs.stdout similarity index 100% rename from src/tools/miri/tests/pass-dep/shims/libc-fs.stdout rename to src/tools/miri/tests/pass-dep/libc/libc-fs.stdout diff --git a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs b/src/tools/miri/tests/pass-dep/libc/libc-mem.rs similarity index 71% rename from src/tools/miri/tests/pass-dep/shims/libc-misc.rs rename to src/tools/miri/tests/pass-dep/libc/libc-mem.rs index 9644920c499c6..5df3ace7496fd 100644 --- a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-mem.rs @@ -1,33 +1,5 @@ -//@ignore-target-windows: No libc on Windows -//@compile-flags: -Zmiri-disable-isolation -#![feature(io_error_more)] -#![feature(pointer_is_aligned_to)] -#![feature(strict_provenance)] - -use std::mem::{self, transmute}; -use std::ptr; - -/// Tests whether each thread has its own `__errno_location`. -fn test_thread_local_errno() { - #[cfg(any(target_os = "illumos", target_os = "solaris"))] - use libc::___errno as __errno_location; - #[cfg(target_os = "linux")] - use libc::__errno_location; - #[cfg(any(target_os = "macos", target_os = "freebsd"))] - use libc::__error as __errno_location; - - unsafe { - *__errno_location() = 0xBEEF; - std::thread::spawn(|| { - assert_eq!(*__errno_location(), 0); - *__errno_location() = 0xBAD1DEA; - assert_eq!(*__errno_location(), 0xBAD1DEA); - }) - .join() - .unwrap(); - assert_eq!(*__errno_location(), 0xBEEF); - } -} +#![feature(strict_provenance, pointer_is_aligned_to)] +use std::{mem, ptr, slice}; fn test_memcpy() { unsafe { @@ -106,49 +78,75 @@ fn test_strcpy() { } } -#[cfg(target_os = "linux")] -fn test_sigrt() { - let min = libc::SIGRTMIN(); - let max = libc::SIGRTMAX(); - - // "The Linux kernel supports a range of 33 different real-time - // signals, numbered 32 to 64" - assert!(min >= 32); - assert!(max >= 32); - assert!(min <= 64); - assert!(max <= 64); - - // "POSIX.1-2001 requires that an implementation support at least - // _POSIX_RTSIG_MAX (8) real-time signals." - assert!(min < max); - assert!(max - min >= 8) -} +fn test_malloc() { + // Test that small allocations sometimes *are* not very aligned. + let saw_unaligned = (0..64).any(|_| unsafe { + let p = libc::malloc(3); + libc::free(p); + (p as usize) % 4 != 0 // find any that this is *not* 4-aligned + }); + assert!(saw_unaligned); + + unsafe { + let p1 = libc::malloc(20); + p1.write_bytes(0u8, 20); -fn test_dlsym() { - let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, b"notasymbol\0".as_ptr().cast()) }; - assert!(addr as usize == 0); + // old size < new size + let p2 = libc::realloc(p1, 40); + let slice = slice::from_raw_parts(p2 as *const u8, 20); + assert_eq!(&slice, &[0_u8; 20]); - let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, b"isatty\0".as_ptr().cast()) }; - assert!(addr as usize != 0); - let isatty: extern "C" fn(i32) -> i32 = unsafe { transmute(addr) }; - assert_eq!(isatty(999), 0); - let errno = std::io::Error::last_os_error().raw_os_error().unwrap(); - assert_eq!(errno, libc::EBADF); + // old size == new size + let p3 = libc::realloc(p2, 40); + let slice = slice::from_raw_parts(p3 as *const u8, 20); + assert_eq!(&slice, &[0_u8; 20]); + + // old size > new size + let p4 = libc::realloc(p3, 10); + let slice = slice::from_raw_parts(p4 as *const u8, 10); + assert_eq!(&slice, &[0_u8; 10]); + + libc::free(p4); + } + + unsafe { + // Realloc with size 0 is okay for the null pointer (and acts like `malloc(0)`) + let p2 = libc::realloc(ptr::null_mut(), 0); + assert!(!p2.is_null()); + libc::free(p2); + } + + unsafe { + let p1 = libc::realloc(ptr::null_mut(), 20); + assert!(!p1.is_null()); + + libc::free(p1); + } } -#[cfg(not(any(target_os = "macos", target_os = "illumos")))] -fn test_reallocarray() { +fn test_calloc() { unsafe { - let mut p = libc::reallocarray(std::ptr::null_mut(), 4096, 2); - assert!(!p.is_null()); - libc::free(p); - p = libc::malloc(16); - let r = libc::reallocarray(p, 2, 32); - assert!(!r.is_null()); - libc::free(r); + let p1 = libc::calloc(0, 0); + assert!(!p1.is_null()); + libc::free(p1); + + let p2 = libc::calloc(20, 0); + assert!(!p2.is_null()); + libc::free(p2); + + let p3 = libc::calloc(0, 20); + assert!(!p3.is_null()); + libc::free(p3); + + let p4 = libc::calloc(4, 8); + assert!(!p4.is_null()); + let slice = slice::from_raw_parts(p4 as *const u8, 4 * 8); + assert_eq!(&slice, &[0_u8; 4 * 8]); + libc::free(p4); } } +#[cfg(not(target_os = "windows"))] fn test_memalign() { // A normal allocation. unsafe { @@ -225,18 +223,37 @@ fn test_memalign() { } } -fn main() { - test_thread_local_errno(); - - test_dlsym(); - - test_memcpy(); - test_strcpy(); +#[cfg(not(any( + target_os = "windows", + target_os = "macos", + target_os = "illumos", + target_os = "solaris" +)))] +fn test_reallocarray() { + unsafe { + let mut p = libc::reallocarray(std::ptr::null_mut(), 4096, 2); + assert!(!p.is_null()); + libc::free(p); + p = libc::malloc(16); + let r = libc::reallocarray(p, 2, 32); + assert!(!r.is_null()); + libc::free(r); + } +} +fn main() { + test_malloc(); + test_calloc(); + #[cfg(not(target_os = "windows"))] test_memalign(); - #[cfg(not(any(target_os = "macos", target_os = "illumos")))] + #[cfg(not(any( + target_os = "windows", + target_os = "macos", + target_os = "illumos", + target_os = "solaris" + )))] test_reallocarray(); - #[cfg(target_os = "linux")] - test_sigrt(); + test_memcpy(); + test_strcpy(); } diff --git a/src/tools/miri/tests/pass-dep/libc/libc-misc.rs b/src/tools/miri/tests/pass-dep/libc/libc-misc.rs new file mode 100644 index 0000000000000..736e0bf8eb7fd --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/libc-misc.rs @@ -0,0 +1,68 @@ +//@ignore-target-windows: only very limited libc on Windows +//@compile-flags: -Zmiri-disable-isolation +#![feature(io_error_more)] +#![feature(pointer_is_aligned_to)] +#![feature(strict_provenance)] + +use std::mem::transmute; + +/// Tests whether each thread has its own `__errno_location`. +fn test_thread_local_errno() { + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + use libc::___errno as __errno_location; + #[cfg(target_os = "linux")] + use libc::__errno_location; + #[cfg(any(target_os = "macos", target_os = "freebsd"))] + use libc::__error as __errno_location; + + unsafe { + *__errno_location() = 0xBEEF; + std::thread::spawn(|| { + assert_eq!(*__errno_location(), 0); + *__errno_location() = 0xBAD1DEA; + assert_eq!(*__errno_location(), 0xBAD1DEA); + }) + .join() + .unwrap(); + assert_eq!(*__errno_location(), 0xBEEF); + } +} + +#[cfg(target_os = "linux")] +fn test_sigrt() { + let min = libc::SIGRTMIN(); + let max = libc::SIGRTMAX(); + + // "The Linux kernel supports a range of 33 different real-time + // signals, numbered 32 to 64" + assert!(min >= 32); + assert!(max >= 32); + assert!(min <= 64); + assert!(max <= 64); + + // "POSIX.1-2001 requires that an implementation support at least + // _POSIX_RTSIG_MAX (8) real-time signals." + assert!(min < max); + assert!(max - min >= 8) +} + +fn test_dlsym() { + let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, b"notasymbol\0".as_ptr().cast()) }; + assert!(addr as usize == 0); + + let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, b"isatty\0".as_ptr().cast()) }; + assert!(addr as usize != 0); + let isatty: extern "C" fn(i32) -> i32 = unsafe { transmute(addr) }; + assert_eq!(isatty(999), 0); + let errno = std::io::Error::last_os_error().raw_os_error().unwrap(); + assert_eq!(errno, libc::EBADF); +} + +fn main() { + test_thread_local_errno(); + + test_dlsym(); + + #[cfg(target_os = "linux")] + test_sigrt(); +} diff --git a/src/tools/miri/tests/pass-dep/shims/libc-random.rs b/src/tools/miri/tests/pass-dep/libc/libc-random.rs similarity index 100% rename from src/tools/miri/tests/pass-dep/shims/libc-random.rs rename to src/tools/miri/tests/pass-dep/libc/libc-random.rs diff --git a/src/tools/miri/tests/pass-dep/shims/libc-time.rs b/src/tools/miri/tests/pass-dep/libc/libc-time.rs similarity index 98% rename from src/tools/miri/tests/pass-dep/shims/libc-time.rs rename to src/tools/miri/tests/pass-dep/libc/libc-time.rs index 69c75bd8caf3c..ea1e49a072571 100644 --- a/src/tools/miri/tests/pass-dep/shims/libc-time.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-time.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: no libc on Windows +//@ignore-target-windows: no libc time APIs on Windows //@compile-flags: -Zmiri-disable-isolation use std::ffi::CStr; use std::{env, mem, ptr}; diff --git a/src/tools/miri/tests/pass-dep/shims/mmap.rs b/src/tools/miri/tests/pass-dep/libc/mmap.rs similarity index 99% rename from src/tools/miri/tests/pass-dep/shims/mmap.rs rename to src/tools/miri/tests/pass-dep/libc/mmap.rs index 5acdedc67bf71..a0787c689077d 100644 --- a/src/tools/miri/tests/pass-dep/shims/mmap.rs +++ b/src/tools/miri/tests/pass-dep/libc/mmap.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No mmap on Windows //@compile-flags: -Zmiri-disable-isolation -Zmiri-permissive-provenance #![feature(strict_provenance)] diff --git a/src/tools/miri/tests/pass-dep/shims/pthread-sync.rs b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs similarity index 99% rename from src/tools/miri/tests/pass-dep/shims/pthread-sync.rs rename to src/tools/miri/tests/pass-dep/libc/pthread-sync.rs index 12d3f2b6f142f..142752621280a 100644 --- a/src/tools/miri/tests/pass-dep/shims/pthread-sync.rs +++ b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows // We use `yield` to test specific interleavings, so disable automatic preemption. //@compile-flags: -Zmiri-preemption-rate=0 #![feature(sync_unsafe_cell)] diff --git a/src/tools/miri/tests/pass-dep/shims/pthread-threadname.rs b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs similarity index 97% rename from src/tools/miri/tests/pass-dep/shims/pthread-threadname.rs rename to src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs index bc782044d4d80..4c4f542dfd4cd 100644 --- a/src/tools/miri/tests/pass-dep/shims/pthread-threadname.rs +++ b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: No libc on Windows +//@ignore-target-windows: No pthreads on Windows use std::ffi::CStr; #[cfg(not(target_os = "freebsd"))] use std::ffi::CString; diff --git a/src/tools/miri/tests/pass-dep/malloc.rs b/src/tools/miri/tests/pass-dep/malloc.rs deleted file mode 100644 index 35cd137931fd6..0000000000000 --- a/src/tools/miri/tests/pass-dep/malloc.rs +++ /dev/null @@ -1,48 +0,0 @@ -//@ignore-target-windows: No libc on Windows - -use core::{ptr, slice}; - -fn main() { - // Test that small allocations sometimes *are* not very aligned. - let saw_unaligned = (0..64).any(|_| unsafe { - let p = libc::malloc(3); - libc::free(p); - (p as usize) % 4 != 0 // find any that this is *not* 4-aligned - }); - assert!(saw_unaligned); - - unsafe { - // Use calloc for initialized memory - let p1 = libc::calloc(20, 1); - - // old size < new size - let p2 = libc::realloc(p1, 40); - let slice = slice::from_raw_parts(p2 as *const u8, 20); - assert_eq!(&slice, &[0_u8; 20]); - - // old size == new size - let p3 = libc::realloc(p2, 40); - let slice = slice::from_raw_parts(p3 as *const u8, 20); - assert_eq!(&slice, &[0_u8; 20]); - - // old size > new size - let p4 = libc::realloc(p3, 10); - let slice = slice::from_raw_parts(p4 as *const u8, 10); - assert_eq!(&slice, &[0_u8; 10]); - - libc::free(p4); - } - - unsafe { - // Realloc with size 0 is okay for the null pointer - let p2 = libc::realloc(ptr::null_mut(), 0); - assert!(p2.is_null()); - } - - unsafe { - let p1 = libc::realloc(ptr::null_mut(), 20); - assert!(!p1.is_null()); - - libc::free(p1); - } -} diff --git a/src/tools/miri/tests/pass-dep/rand.rs b/src/tools/miri/tests/pass-dep/rand.rs deleted file mode 100644 index 0dce6d86cf481..0000000000000 --- a/src/tools/miri/tests/pass-dep/rand.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@compile-flags: -Zmiri-strict-provenance -use rand::prelude::*; - -// Test using the `rand` crate to generate randomness. -fn main() { - // Fully deterministic seeding. - let mut rng = SmallRng::seed_from_u64(42); - let _val = rng.gen::(); - let _val = rng.gen::(); - let _val = rng.gen::(); - - // Try seeding with "real" entropy. - let mut rng = SmallRng::from_entropy(); - let _val = rng.gen::(); - let _val = rng.gen::(); - let _val = rng.gen::(); - - // Also try per-thread RNG. - let mut rng = rand::thread_rng(); - let _val = rng.gen::(); - let _val = rng.gen::(); - let _val = rng.gen::(); -} diff --git a/src/tools/miri/tests/pass-dep/wcslen.rs b/src/tools/miri/tests/pass-dep/wcslen.rs new file mode 100644 index 0000000000000..c5c9d99247965 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/wcslen.rs @@ -0,0 +1,20 @@ +fn to_c_wchar_t_str(s: &str) -> Vec { + let mut r = Vec::::new(); + for c in s.bytes() { + if c == 0 { + panic!("can't contain a null character"); + } + if c >= 128 { + panic!("only ASCII supported"); + } + r.push(c.into()); + } + r.push(0); + r +} + +pub fn main() { + let s = to_c_wchar_t_str("Rust"); + let len = unsafe { libc::wcslen(s.as_ptr()) }; + assert_eq!(len, 4); +} diff --git a/src/tools/miri/tests/pass/function_calls/abi_compat.rs b/src/tools/miri/tests/pass/function_calls/abi_compat.rs index 14fd2d333d4fb..136660a305aff 100644 --- a/src/tools/miri/tests/pass/function_calls/abi_compat.rs +++ b/src/tools/miri/tests/pass/function_calls/abi_compat.rs @@ -70,7 +70,7 @@ fn main() { test_abi_compat(0usize, 0u64); test_abi_compat(0isize, 0i64); } - test_abi_compat(42u32, num::NonZeroU32::new(1).unwrap()); + test_abi_compat(42u32, num::NonZero::new(1u32).unwrap()); // - `char` and `u32`. test_abi_compat(42u32, 'x'); // - Reference/pointer types with the same pointee. @@ -86,9 +86,9 @@ fn main() { // - Guaranteed null-pointer-optimizations (RFC 3391). test_abi_compat(&0u32 as *const u32, Some(&0u32)); test_abi_compat(main as fn(), Some(main as fn())); - test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap())); + test_abi_compat(0u32, Some(num::NonZero::new(1u32).unwrap())); test_abi_compat(&0u32 as *const u32, Some(Wrapper(&0u32))); - test_abi_compat(0u32, Some(Wrapper(num::NonZeroU32::new(1).unwrap()))); + test_abi_compat(0u32, Some(Wrapper(num::NonZero::new(1u32).unwrap()))); // These must work for *any* type, since we guarantee that `repr(transparent)` is ABI-compatible // with the wrapped field. @@ -102,7 +102,7 @@ fn main() { test_abi_newtype::<[u32; 2]>(); test_abi_newtype::<[u32; 32]>(); test_abi_newtype::>(); - test_abi_newtype::>(); + test_abi_newtype::>>(); // Extra test for assumptions made by arbitrary-self-dyn-receivers. // This is interesting since these types are not `repr(transparent)`. So this is not part of our diff --git a/src/tools/miri/tests/pass/shims/available-parallelism-miri-num-cpus.rs b/src/tools/miri/tests/pass/shims/available-parallelism-miri-num-cpus.rs index 137fa51024975..0d96bc2f5e737 100644 --- a/src/tools/miri/tests/pass/shims/available-parallelism-miri-num-cpus.rs +++ b/src/tools/miri/tests/pass/shims/available-parallelism-miri-num-cpus.rs @@ -1,8 +1,8 @@ //@compile-flags: -Zmiri-num-cpus=1024 -use std::num::NonZeroUsize; +use std::num::NonZero; use std::thread::available_parallelism; fn main() { - assert_eq!(available_parallelism().unwrap(), NonZeroUsize::new(1024).unwrap()); + assert_eq!(available_parallelism().unwrap(), NonZero::new(1024).unwrap()); } diff --git a/src/tools/miri/tests/pass/shims/fs-symlink.rs b/src/tools/miri/tests/pass/shims/fs-symlink.rs new file mode 100644 index 0000000000000..4d5103b24c32d --- /dev/null +++ b/src/tools/miri/tests/pass/shims/fs-symlink.rs @@ -0,0 +1,50 @@ +// Symlink tests are separate since they don't in general work on a Windows host. +//@ignore-host-windows: creating symlinks requires admin permissions on Windows +//@ignore-target-windows: File handling is not implemented yet +//@compile-flags: -Zmiri-disable-isolation + +use std::fs::{read_link, remove_file, File}; +use std::io::{Read, Result}; +use std::path::Path; + +#[path = "../../utils/mod.rs"] +mod utils; + +fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> { + // Test that the file metadata is correct. + let metadata = path.metadata()?; + // `path` should point to a file. + assert!(metadata.is_file()); + // The size of the file must be equal to the number of written bytes. + assert_eq!(bytes.len() as u64, metadata.len()); + Ok(()) +} + +fn main() { + let bytes = b"Hello, World!\n"; + let path = utils::prepare_with_content("miri_test_fs_link_target.txt", bytes); + let symlink_path = utils::prepare("miri_test_fs_symlink.txt"); + + // Creating a symbolic link should succeed. + #[cfg(unix)] + std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); + #[cfg(windows)] + std::os::windows::fs::symlink_file(&path, &symlink_path).unwrap(); + // Test that the symbolic link has the same contents as the file. + let mut symlink_file = File::open(&symlink_path).unwrap(); + let mut contents = Vec::new(); + symlink_file.read_to_end(&mut contents).unwrap(); + assert_eq!(bytes, contents.as_slice()); + + // Test that metadata of a symbolic link (i.e., the file it points to) is correct. + check_metadata(bytes, &symlink_path).unwrap(); + // Test that the metadata of a symbolic link is correct when not following it. + assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink()); + // Check that we can follow the link. + assert_eq!(read_link(&symlink_path).unwrap(), path); + // Removing symbolic link should succeed. + remove_file(&symlink_path).unwrap(); + + // Removing file should succeed. + remove_file(&path).unwrap(); +} diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 8a500b857bca6..35980fad15dd0 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -1,21 +1,17 @@ //@ignore-target-windows: File handling is not implemented yet //@compile-flags: -Zmiri-disable-isolation -// If this test is failing for you locally, you can try -// 1. Deleting the files `/tmp/miri_*` -// 2. Setting `MIRI_TEMP` or `TMPDIR` to a different directory, without the `miri_*` files - #![feature(io_error_more)] #![feature(io_error_uncategorized)] use std::collections::HashMap; use std::ffi::OsString; use std::fs::{ - canonicalize, create_dir, read_dir, read_link, remove_dir, remove_dir_all, remove_file, rename, - File, OpenOptions, + canonicalize, create_dir, read_dir, remove_dir, remove_dir_all, remove_file, rename, File, + OpenOptions, }; use std::io::{Error, ErrorKind, IsTerminal, Read, Result, Seek, SeekFrom, Write}; -use std::path::{Path, PathBuf}; +use std::path::Path; #[path = "../../utils/mod.rs"] mod utils; @@ -29,7 +25,6 @@ fn main() { test_metadata(); test_file_set_len(); test_file_sync(); - test_symlink(); test_errors(); test_rename(); test_directory(); @@ -37,30 +32,6 @@ fn main() { test_from_raw_os_error(); } -/// Prepare: compute filename and make sure the file does not exist. -fn prepare(filename: &str) -> PathBuf { - let path = utils::tmp().join(filename); - // Clean the paths for robustness. - remove_file(&path).ok(); - path -} - -/// Prepare directory: compute directory name and make sure it does not exist. -fn prepare_dir(dirname: &str) -> PathBuf { - let path = utils::tmp().join(&dirname); - // Clean the directory for robustness. - remove_dir_all(&path).ok(); - path -} - -/// Prepare like above, and also write some initial content to the file. -fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf { - let path = prepare(filename); - let mut file = File::create(&path).unwrap(); - file.write(content).unwrap(); - path -} - fn test_path_conversion() { let tmp = utils::tmp(); assert!(tmp.is_absolute(), "{:?} is not absolute", tmp); @@ -69,7 +40,7 @@ fn test_path_conversion() { fn test_file() { let bytes = b"Hello, World!\n"; - let path = prepare("miri_test_fs_file.txt"); + let path = utils::prepare("miri_test_fs_file.txt"); // Test creating, writing and closing a file (closing is tested when `file` is dropped). let mut file = File::create(&path).unwrap(); @@ -96,7 +67,7 @@ fn test_file() { fn test_file_clone() { let bytes = b"Hello, World!\n"; - let path = prepare_with_content("miri_test_fs_file_clone.txt", bytes); + let path = utils::prepare_with_content("miri_test_fs_file_clone.txt", bytes); // Cloning a file should be successful. let file = File::open(&path).unwrap(); @@ -111,7 +82,7 @@ fn test_file_clone() { } fn test_file_create_new() { - let path = prepare("miri_test_fs_file_create_new.txt"); + let path = utils::prepare("miri_test_fs_file_create_new.txt"); // Creating a new file that doesn't yet exist should succeed. OpenOptions::new().write(true).create_new(true).open(&path).unwrap(); @@ -129,7 +100,7 @@ fn test_file_create_new() { fn test_seek() { let bytes = b"Hello, entire World!\n"; - let path = prepare_with_content("miri_test_fs_seek.txt", bytes); + let path = utils::prepare_with_content("miri_test_fs_seek.txt", bytes); let mut file = File::open(&path).unwrap(); let mut contents = Vec::new(); @@ -168,7 +139,7 @@ fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> { fn test_metadata() { let bytes = b"Hello, meta-World!\n"; - let path = prepare_with_content("miri_test_fs_metadata.txt", bytes); + let path = utils::prepare_with_content("miri_test_fs_metadata.txt", bytes); // Test that metadata of an absolute path is correct. check_metadata(bytes, &path).unwrap(); @@ -182,7 +153,7 @@ fn test_metadata() { fn test_file_set_len() { let bytes = b"Hello, World!\n"; - let path = prepare_with_content("miri_test_fs_set_len.txt", bytes); + let path = utils::prepare_with_content("miri_test_fs_set_len.txt", bytes); // Test extending the file let mut file = OpenOptions::new().read(true).write(true).open(&path).unwrap(); @@ -208,7 +179,7 @@ fn test_file_set_len() { fn test_file_sync() { let bytes = b"Hello, World!\n"; - let path = prepare_with_content("miri_test_fs_sync.txt", bytes); + let path = utils::prepare_with_content("miri_test_fs_sync.txt", bytes); // Test that we can call sync_data and sync_all (can't readily test effects of this operation) let file = OpenOptions::new().write(true).open(&path).unwrap(); @@ -223,38 +194,9 @@ fn test_file_sync() { remove_file(&path).unwrap(); } -fn test_symlink() { - let bytes = b"Hello, World!\n"; - let path = prepare_with_content("miri_test_fs_link_target.txt", bytes); - let symlink_path = prepare("miri_test_fs_symlink.txt"); - - // Creating a symbolic link should succeed. - #[cfg(unix)] - std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); - #[cfg(windows)] - std::os::windows::fs::symlink_file(&path, &symlink_path).unwrap(); - // Test that the symbolic link has the same contents as the file. - let mut symlink_file = File::open(&symlink_path).unwrap(); - let mut contents = Vec::new(); - symlink_file.read_to_end(&mut contents).unwrap(); - assert_eq!(bytes, contents.as_slice()); - - // Test that metadata of a symbolic link (i.e., the file it points to) is correct. - check_metadata(bytes, &symlink_path).unwrap(); - // Test that the metadata of a symbolic link is correct when not following it. - assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink()); - // Check that we can follow the link. - assert_eq!(read_link(&symlink_path).unwrap(), path); - // Removing symbolic link should succeed. - remove_file(&symlink_path).unwrap(); - - // Removing file should succeed. - remove_file(&path).unwrap(); -} - fn test_errors() { let bytes = b"Hello, World!\n"; - let path = prepare("miri_test_fs_errors.txt"); + let path = utils::prepare("miri_test_fs_errors.txt"); // The following tests also check that the `__errno_location()` shim is working properly. // Opening a non-existing file should fail with a "not found" error. @@ -269,8 +211,8 @@ fn test_errors() { fn test_rename() { // Renaming a file should succeed. - let path1 = prepare("miri_test_fs_rename_source.txt"); - let path2 = prepare("miri_test_fs_rename_destination.txt"); + let path1 = utils::prepare("miri_test_fs_rename_source.txt"); + let path2 = utils::prepare("miri_test_fs_rename_destination.txt"); let file = File::create(&path1).unwrap(); drop(file); @@ -289,7 +231,7 @@ fn test_rename() { } fn test_canonicalize() { - let dir_path = prepare_dir("miri_test_fs_dir"); + let dir_path = utils::prepare_dir("miri_test_fs_dir"); create_dir(&dir_path).unwrap(); let path = dir_path.join("test_file"); drop(File::create(&path).unwrap()); @@ -301,7 +243,7 @@ fn test_canonicalize() { } fn test_directory() { - let dir_path = prepare_dir("miri_test_fs_dir"); + let dir_path = utils::prepare_dir("miri_test_fs_dir"); // Creating a directory should succeed. create_dir(&dir_path).unwrap(); // Test that the metadata of a directory is correct. diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs index efeefbe29fbce..3a8b098ccbe36 100644 --- a/src/tools/miri/tests/ui.rs +++ b/src/tools/miri/tests/ui.rs @@ -1,5 +1,5 @@ use std::ffi::OsString; -use std::num::NonZeroUsize; +use std::num::NonZero; use std::path::{Path, PathBuf}; use std::sync::OnceLock; use std::{env, process::Command}; @@ -27,11 +27,12 @@ pub fn flagsplit(flags: &str) -> Vec { flags.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string).collect() } -// Build the shared object file for testing external C function calls. -fn build_so_for_c_ffi_tests() -> PathBuf { +// Build the shared object file for testing native function calls. +fn build_native_lib() -> PathBuf { let cc = option_env!("CC").unwrap_or("cc"); // Target directory that we can write to. - let so_target_dir = Path::new(&env::var_os("CARGO_TARGET_DIR").unwrap()).join("miri-extern-so"); + let so_target_dir = + Path::new(&env::var_os("CARGO_TARGET_DIR").unwrap()).join("miri-native-lib"); // Create the directory if it does not already exist. std::fs::create_dir_all(&so_target_dir) .expect("Failed to create directory for shared object file"); @@ -41,18 +42,18 @@ fn build_so_for_c_ffi_tests() -> PathBuf { "-shared", "-o", so_file_path.to_str().unwrap(), - "tests/extern-so/test.c", + "tests/native-lib/test.c", // Only add the functions specified in libcode.version to the shared object file. // This is to avoid automatically adding `malloc`, etc. // Source: https://anadoxin.org/blog/control-over-symbol-exports-in-gcc.html/ "-fPIC", - "-Wl,--version-script=tests/extern-so/libtest.map", + "-Wl,--version-script=tests/native-lib/libtest.map", ]) .output() - .expect("failed to generate shared object file for testing external C function calls"); + .expect("failed to generate shared object file for testing native function calls"); if !cc_output.status.success() { panic!( - "error in generating shared object file for testing external C function calls:\n{}", + "error generating shared object file for testing native function calls:\n{}", String::from_utf8_lossy(&cc_output.stderr), ); } @@ -76,7 +77,7 @@ fn miri_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) -> edition: Some("2021".into()), // keep in sync with `./miri run` threads: std::env::var("MIRI_TEST_THREADS") .ok() - .map(|threads| NonZeroUsize::new(threads.parse().unwrap()).unwrap()), + .map(|threads| NonZero::new(threads.parse().unwrap()).unwrap()), ..Config::rustc(path) }; @@ -132,13 +133,12 @@ fn run_tests( config.program.args.push("--target".into()); config.program.args.push(target.into()); - // If we're testing the extern-so functionality, then build the shared object file for testing + // If we're testing the native-lib functionality, then build the shared object file for testing // external C function calls and push the relevant compiler flag. - if path.starts_with("tests/extern-so/") { - assert!(cfg!(target_os = "linux")); - let so_file_path = build_so_for_c_ffi_tests(); - let mut flag = std::ffi::OsString::from("-Zmiri-extern-so-file="); - flag.push(so_file_path.into_os_string()); + if path.starts_with("tests/native-lib/") { + let native_lib = build_native_lib(); + let mut flag = std::ffi::OsString::from("-Zmiri-native-lib="); + flag.push(native_lib.into_os_string()); config.program.args.push(flag); } @@ -292,10 +292,10 @@ fn main() -> Result<()> { tmpdir.path(), )?; if cfg!(target_os = "linux") { - ui(Mode::Pass, "tests/extern-so/pass", &target, WithoutDependencies, tmpdir.path())?; + ui(Mode::Pass, "tests/native-lib/pass", &target, WithoutDependencies, tmpdir.path())?; ui( Mode::Fail { require_patterns: true, rustfix: RustfixMode::Disabled }, - "tests/extern-so/fail", + "tests/native-lib/fail", &target, WithoutDependencies, tmpdir.path(), diff --git a/src/tools/miri/tests/utils/fs.rs b/src/tools/miri/tests/utils/fs.rs index 0242a2280689a..7340908626fdf 100644 --- a/src/tools/miri/tests/utils/fs.rs +++ b/src/tools/miri/tests/utils/fs.rs @@ -1,4 +1,5 @@ use std::ffi::OsString; +use std::fs; use std::path::PathBuf; use super::miri_extern; @@ -27,3 +28,26 @@ pub fn tmp() -> PathBuf { // These are host paths. We need to convert them to the target. host_to_target_path(path) } + +/// Prepare: compute filename and make sure the file does not exist. +pub fn prepare(filename: &str) -> PathBuf { + let path = tmp().join(filename); + // Clean the paths for robustness. + fs::remove_file(&path).ok(); + path +} + +/// Prepare like above, and also write some initial content to the file. +pub fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf { + let path = prepare(filename); + fs::write(&path, content).unwrap(); + path +} + +/// Prepare directory: compute directory name and make sure it does not exist. +pub fn prepare_dir(dirname: &str) -> PathBuf { + let path = tmp().join(&dirname); + // Clean the directory for robustness. + fs::remove_dir_all(&path).ok(); + path +} diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml index 4cb6acb394ccb..1ff410e723afe 100644 --- a/src/tools/opt-dist/Cargo.toml +++ b/src/tools/opt-dist/Cargo.toml @@ -16,7 +16,7 @@ camino = "1" reqwest = { version = "0.11", features = ["blocking"] } zip = { version = "0.6", default-features = false, features = ["deflate"] } tar = "0.4" -xz = "0.1" +xz = { version = "0.1", package = "xz2" } serde = { version = "1", features = ["derive"] } serde_json = "1" glob = "0.3" diff --git a/src/tools/run-make-support/src/cc.rs b/src/tools/run-make-support/src/cc.rs index 4082639f618a1..a67f5c8a9ee43 100644 --- a/src/tools/run-make-support/src/cc.rs +++ b/src/tools/run-make-support/src/cc.rs @@ -73,7 +73,7 @@ impl Cc { } /// Get the [`Output`][::std::process::Output] of the finished process. - pub fn output(&mut self) -> ::std::process::Output { + pub fn command_output(&mut self) -> ::std::process::Output { self.cmd.output().expect("failed to get output of finished process") } } diff --git a/src/tools/run-make-support/src/clang.rs b/src/tools/run-make-support/src/clang.rs index c30ba29ed76d6..6ccce67b250db 100644 --- a/src/tools/run-make-support/src/clang.rs +++ b/src/tools/run-make-support/src/clang.rs @@ -72,7 +72,7 @@ impl Clang { } /// Get the [`Output`][::std::process::Output] of the finished process. - pub fn output(&mut self) -> ::std::process::Output { + pub fn command_output(&mut self) -> ::std::process::Output { self.cmd.output().expect("failed to get output of finished process") } } diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index d040b05f20e82..cc81d23a8ff01 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -54,6 +54,15 @@ pub fn static_lib(name: &str) -> PathBuf { tmp_dir().join(static_lib_name(name)) } +pub fn python_command() -> Command { + let python_path = std::env::var("PYTHON").expect("PYTHON environment variable does not exist"); + Command::new(python_path) +} + +pub fn source_path() -> PathBuf { + std::env::var("S").expect("S variable does not exist").into() +} + /// Construct the static library name based on the platform. pub fn static_lib_name(name: &str) -> String { // See tools.mk (irrelevant lines omitted): @@ -164,7 +173,7 @@ pub fn set_host_rpath(cmd: &mut Command) { /// /// impl CommandWrapper { /// /// Get the [`Output`][::std::process::Output] of the finished process. -/// pub fn output(&mut self) -> Output { /* ... */ } // <- required `output()` method +/// pub fn command_output(&mut self) -> Output { /* ... */ } // <- required `command_output()` method /// } /// /// crate::impl_common_helpers!(CommandWrapper); @@ -242,7 +251,7 @@ macro_rules! impl_common_helpers { let caller_location = ::std::panic::Location::caller(); let caller_line_number = caller_location.line(); - let output = self.output(); + let output = self.command_output(); if !output.status.success() { handle_failed_output(&self.cmd, output, caller_line_number); } @@ -255,7 +264,7 @@ macro_rules! impl_common_helpers { let caller_location = ::std::panic::Location::caller(); let caller_line_number = caller_location.line(); - let output = self.output(); + let output = self.command_output(); if output.status.success() { handle_failed_output(&self.cmd, output, caller_line_number); } diff --git a/src/tools/run-make-support/src/llvm_readobj.rs b/src/tools/run-make-support/src/llvm_readobj.rs index 4e1f2b002f301..f114aacfa3fc7 100644 --- a/src/tools/run-make-support/src/llvm_readobj.rs +++ b/src/tools/run-make-support/src/llvm_readobj.rs @@ -44,7 +44,7 @@ impl LlvmReadobj { /// Get the [`Output`][::std::process::Output] of the finished process. #[track_caller] - pub fn output(&mut self) -> ::std::process::Output { + pub fn command_output(&mut self) -> ::std::process::Output { self.cmd.output().expect("failed to get output of finished process") } } diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index 37539528ab3fc..1671a01860ae4 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -1,5 +1,5 @@ use std::env; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::io::Write; use std::path::Path; use std::process::{Command, Output, Stdio}; @@ -91,6 +91,13 @@ impl Rustc { self } + /// Specify path to the output file. + pub fn output>(&mut self, path: P) -> &mut Self { + self.cmd.arg("-o"); + self.cmd.arg(path.as_ref()); + self + } + /// 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}")); @@ -169,9 +176,16 @@ impl Rustc { self } + /// Specify the crate name. + pub fn crate_name>(&mut self, name: S) -> &mut Self { + self.cmd.arg("--crate-name"); + self.cmd.arg(name.as_ref()); + self + } + /// Get the [`Output`][::std::process::Output] of the finished process. #[track_caller] - pub fn output(&mut self) -> ::std::process::Output { + pub fn command_output(&mut self) -> ::std::process::Output { // let's make sure we piped all the input and outputs self.cmd.stdin(Stdio::piped()); self.cmd.stdout(Stdio::piped()); @@ -196,7 +210,7 @@ impl Rustc { let caller_location = std::panic::Location::caller(); let caller_line_number = caller_location.line(); - let output = self.output(); + let output = self.command_output(); if output.status.code().unwrap() != code { handle_failed_output(&self.cmd, output, caller_line_number); } diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs index c2c4f2e68e2f8..75ca1fc29747f 100644 --- a/src/tools/run-make-support/src/rustdoc.rs +++ b/src/tools/run-make-support/src/rustdoc.rs @@ -1,4 +1,5 @@ use std::env; +use std::ffi::OsStr; use std::io::Write; use std::path::Path; use std::process::{Command, Output, Stdio}; @@ -45,12 +46,34 @@ impl Rustdoc { Self { cmd, stdin: None } } + /// Specify where an external library is located. + pub fn extern_>(&mut self, crate_name: &str, path: P) -> &mut Self { + assert!( + !crate_name.contains(|c: char| c.is_whitespace() || c == '\\' || c == '/'), + "crate name cannot contain whitespace or path separators" + ); + + let path = path.as_ref().to_string_lossy(); + + self.cmd.arg("--extern"); + self.cmd.arg(format!("{crate_name}={path}")); + + self + } + /// Specify path to the input file. pub fn input>(&mut self, path: P) -> &mut Self { self.cmd.arg(path.as_ref()); self } + /// Specify path to the output folder. + pub fn output>(&mut self, path: P) -> &mut Self { + self.cmd.arg("-o"); + self.cmd.arg(path.as_ref()); + self + } + /// Specify output directory. pub fn out_dir>(&mut self, path: P) -> &mut Self { self.cmd.arg("--out-dir").arg(path.as_ref()); @@ -73,7 +96,7 @@ impl Rustdoc { /// Get the [`Output`][::std::process::Output] of the finished process. #[track_caller] - pub fn output(&mut self) -> ::std::process::Output { + pub fn command_output(&mut self) -> ::std::process::Output { // let's make sure we piped all the input and outputs self.cmd.stdin(Stdio::piped()); self.cmd.stdout(Stdio::piped()); @@ -93,12 +116,33 @@ impl Rustdoc { } } + /// Specify the edition year. + pub fn edition(&mut self, edition: &str) -> &mut Self { + self.cmd.arg("--edition"); + self.cmd.arg(edition); + 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); + self + } + + /// Specify the crate name. + pub fn crate_name>(&mut self, name: S) -> &mut Self { + self.cmd.arg("--crate-name"); + self.cmd.arg(name.as_ref()); + self + } + #[track_caller] 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.output(); + let output = self.command_output(); if output.status.code().unwrap() != code { handle_failed_output(&self.cmd, output, caller_line_number); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs index dd949e26c2ab2..d9fd029d378c7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs @@ -6,8 +6,8 @@ use base_db::salsa::Cycle; use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy}; use hir_def::{ layout::{ - Abi, FieldsShape, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions, Scalar, Size, - StructKind, TargetDataLayout, WrappingRange, + Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions, + Scalar, Size, StructKind, TargetDataLayout, WrappingRange, }, LocalFieldId, StructId, }; @@ -264,10 +264,10 @@ pub fn layout_of_ty_query( ), chalk_ir::Scalar::Float(f) => scalar( dl, - match f { - FloatTy::F32 => Primitive::F32, - FloatTy::F64 => Primitive::F64, - }, + Primitive::Float(match f { + FloatTy::F32 => Float::F32, + FloatTy::F64 => Float::F64, + }), ), }, TyKind::Tuple(len, tys) => { diff --git a/src/tools/rustfmt/src/imports.rs b/src/tools/rustfmt/src/imports.rs index 09f6e75233880..2da746295fc96 100644 --- a/src/tools/rustfmt/src/imports.rs +++ b/src/tools/rustfmt/src/imports.rs @@ -458,7 +458,9 @@ impl UseTree { version, }); } - UseTreeKind::Nested(ref list) => { + UseTreeKind::Nested { + items: ref list, .. + } => { // Extract comments between nested use items. // This needs to be done before sorting use items. let items = itemize_list( diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index d4d6c1460ceec..d742368292035 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -44,7 +44,6 @@ run-make/dep-graph/Makefile run-make/dep-info-doesnt-run-much/Makefile run-make/dep-info-spaces/Makefile run-make/dep-info/Makefile -run-make/doctests-runtool/Makefile run-make/dump-ice-to-disk/Makefile run-make/dump-mono-stats/Makefile run-make/duplicate-output-flavors/Makefile @@ -245,18 +244,13 @@ run-make/rlib-format-packed-bundled-libs-3/Makefile run-make/rlib-format-packed-bundled-libs/Makefile run-make/rmeta-preferred/Makefile run-make/rustc-macro-dep-files/Makefile -run-make/rustdoc-error-lines/Makefile run-make/rustdoc-io-error/Makefile -run-make/rustdoc-map-file/Makefile -run-make/rustdoc-output-path/Makefile run-make/rustdoc-scrape-examples-invalid-expr/Makefile run-make/rustdoc-scrape-examples-macros/Makefile run-make/rustdoc-scrape-examples-multiple/Makefile -run-make/rustdoc-scrape-examples-ordering/Makefile run-make/rustdoc-scrape-examples-remap/Makefile run-make/rustdoc-scrape-examples-test/Makefile run-make/rustdoc-scrape-examples-whitespace/Makefile -run-make/rustdoc-shared-flags/Makefile run-make/rustdoc-target-spec-json-path/Makefile run-make/rustdoc-themes/Makefile run-make/rustdoc-verify-output-files/Makefile diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 1d24c59b356f2..1b73b67b75575 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -395,6 +395,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 4f02a61f7bc7b..a931782e8ccbe 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -3862,7 +3862,6 @@ 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 diff --git a/src/tools/tidy/src/iter_header.rs b/src/tools/tidy/src/iter_header.rs index ae635904607e7..684c789039f6b 100644 --- a/src/tools/tidy/src/iter_header.rs +++ b/src/tools/tidy/src/iter_header.rs @@ -3,6 +3,7 @@ const COMMENT: &str = "//@"; /// A header line, like `//@name: value` consists of the prefix `//@` and the directive /// `name: value`. It is also possibly revisioned, e.g. `//@[revision] name: value`. pub(crate) struct HeaderLine<'ln> { + pub(crate) line_number: usize, pub(crate) revision: Option<&'ln str>, pub(crate) directive: &'ln str, } @@ -11,7 +12,7 @@ pub(crate) struct HeaderLine<'ln> { /// /// Adjusted from compiletest/src/header.rs. pub(crate) fn iter_header<'ln>(contents: &'ln str, it: &mut dyn FnMut(HeaderLine<'ln>)) { - for ln in contents.lines() { + for (line_number, ln) in (1..).zip(contents.lines()) { let ln = ln.trim(); // We're left with potentially `[rev]name: value`. @@ -24,9 +25,9 @@ pub(crate) fn iter_header<'ln>(contents: &'ln str, it: &mut dyn FnMut(HeaderLine panic!("malformed revision directive: expected `//@[rev]`, found `{ln}`"); }; // We trimmed off the `[rev]` portion, left with `name: value`. - it(HeaderLine { revision: Some(revision), directive: remainder.trim() }); + it(HeaderLine { line_number, revision: Some(revision), directive: remainder.trim() }); } else { - it(HeaderLine { revision: None, directive: remainder.trim() }); + it(HeaderLine { line_number, revision: None, directive: remainder.trim() }); } } } diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index c15081a56d1a8..ae9d2b8b8dc87 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -87,6 +87,7 @@ pub mod tests_placement; pub mod tests_revision_unpaired_stdout_stderr; pub mod ui_tests; pub mod unit_tests; +pub mod unknown_revision; pub mod unstable_book; pub mod walk; pub mod x_version; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 77691815830a6..1d2b2e4d03472 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -110,6 +110,7 @@ fn main() { check!(rustdoc_gui_tests, &tests_path); check!(rustdoc_css_themes, &librustdoc_path); check!(known_bug, &crashes_path); + check!(unknown_revision, &tests_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/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs index cb242bff05d1d..c876aae494dd5 100644 --- a/src/tools/tidy/src/target_specific_tests.rs +++ b/src/tools/tidy/src/target_specific_tests.rs @@ -20,7 +20,7 @@ pub fn check(path: &Path, bad: &mut bool) { crate::walk::walk(path, |path, _is_dir| filter_not_rust(path), &mut |entry, content| { let file = entry.path().display(); let mut header_map = BTreeMap::new(); - iter_header(content, &mut |HeaderLine { revision, directive }| { + iter_header(content, &mut |HeaderLine { revision, directive, .. }| { if let Some(value) = directive.strip_prefix(LLVM_COMPONENTS_HEADER) { let info = header_map.entry(revision).or_insert(RevisionInfo::default()); let comp_vec = info.llvm_components.get_or_insert(Vec::new()); diff --git a/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs b/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs index a0773c85bef5e..00edf99a30dbd 100644 --- a/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs +++ b/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs @@ -61,7 +61,7 @@ pub fn check(tests_path: impl AsRef, bad: &mut bool) { let contents = std::fs::read_to_string(test).unwrap(); // Collect directives. - iter_header(&contents, &mut |HeaderLine { revision, directive }| { + iter_header(&contents, &mut |HeaderLine { revision, directive, .. }| { // We're trying to *find* `//@ revision: xxx` directives themselves, not revisioned // directives. if revision.is_some() { diff --git a/src/tools/tidy/src/unknown_revision.rs b/src/tools/tidy/src/unknown_revision.rs new file mode 100644 index 0000000000000..abfff1d632ad8 --- /dev/null +++ b/src/tools/tidy/src/unknown_revision.rs @@ -0,0 +1,114 @@ +//! Checks that test revision names appearing in header directives and error +//! annotations have actually been declared in `revisions`. + +// FIXME(jieyouxu) Ideally these checks would be integrated into compiletest's +// own directive and revision handling, but for now they've been split out as a +// separate `tidy` check to avoid making compiletest even messier. + +use std::collections::{BTreeSet, HashMap, HashSet}; +use std::path::Path; +use std::sync::OnceLock; + +use ignore::DirEntry; +use regex::Regex; + +use crate::iter_header::{iter_header, HeaderLine}; +use crate::walk::{filter_dirs, filter_not_rust, walk}; + +pub fn check(tests_path: impl AsRef, bad: &mut bool) { + walk( + tests_path.as_ref(), + |path, is_dir| { + filter_dirs(path) || filter_not_rust(path) || { + // Auxiliary source files for incremental tests can refer to revisions + // declared by the main file, which this check doesn't handle. + is_dir && path.file_name().is_some_and(|name| name == "auxiliary") + } + }, + &mut |entry, contents| visit_test_file(entry, contents, bad), + ); +} + +fn visit_test_file(entry: &DirEntry, contents: &str, bad: &mut bool) { + let mut revisions = HashSet::new(); + let mut unused_revision_names = HashSet::new(); + + // Maps each mentioned revision to the first line it was mentioned on. + let mut mentioned_revisions = HashMap::<&str, usize>::new(); + let mut add_mentioned_revision = |line_number: usize, revision| { + let first_line = mentioned_revisions.entry(revision).or_insert(line_number); + *first_line = (*first_line).min(line_number); + }; + + // Scan all `//@` headers to find declared revisions and mentioned revisions. + iter_header(contents, &mut |HeaderLine { line_number, revision, directive }| { + if let Some(revs) = directive.strip_prefix("revisions:") { + revisions.extend(revs.split_whitespace()); + } else if let Some(revs) = directive.strip_prefix("unused-revision-names:") { + unused_revision_names.extend(revs.split_whitespace()); + } + + if let Some(revision) = revision { + add_mentioned_revision(line_number, revision); + } + }); + + // If a wildcard appears in `unused-revision-names`, skip all revision name + // checking for this file. + if unused_revision_names.contains(&"*") { + return; + } + + // Scan all `//[rev]~` error annotations to find mentioned revisions. + for_each_error_annotation_revision(contents, &mut |ErrorAnnRev { line_number, revision }| { + add_mentioned_revision(line_number, revision); + }); + + let path = entry.path().display(); + + // Fail if any revision names appear in both places, since that's probably a mistake. + for rev in revisions.intersection(&unused_revision_names).copied().collect::>() { + tidy_error!( + bad, + "revision name [{rev}] appears in both `revisions` and `unused-revision-names` in {path}" + ); + } + + // Compute the set of revisions that were mentioned but not declared, + // sorted by the first line number they appear on. + let mut bad_revisions = mentioned_revisions + .into_iter() + .filter(|(rev, _)| !revisions.contains(rev) && !unused_revision_names.contains(rev)) + .map(|(rev, line_number)| (line_number, rev)) + .collect::>(); + bad_revisions.sort(); + + for (line_number, rev) in bad_revisions { + tidy_error!(bad, "unknown revision [{rev}] at {path}:{line_number}"); + } +} + +struct ErrorAnnRev<'a> { + line_number: usize, + revision: &'a str, +} + +fn for_each_error_annotation_revision<'a>( + contents: &'a str, + callback: &mut dyn FnMut(ErrorAnnRev<'a>), +) { + let error_regex = { + // Simplified from the regex used by `parse_expected` in `src/tools/compiletest/src/errors.rs`, + // because we only care about extracting revision names. + static RE: OnceLock = OnceLock::new(); + RE.get_or_init(|| Regex::new(r"//\[(?[^]]*)\]~").unwrap()) + }; + + for (line_number, line) in (1..).zip(contents.lines()) { + let Some(captures) = error_regex.captures(line) else { continue }; + + for revision in captures.name("revs").unwrap().as_str().split(',') { + callback(ErrorAnnRev { line_number, revision }); + } + } +} diff --git a/tests/auxiliary/rust_test_helpers.c b/tests/auxiliary/rust_test_helpers.c index 965df44c67608..34cc7fd5dfbed 100644 --- a/tests/auxiliary/rust_test_helpers.c +++ b/tests/auxiliary/rust_test_helpers.c @@ -27,10 +27,10 @@ rust_dbg_extern_identity_u8(char u) { return u; } -typedef void *(*dbg_callback)(void*); +typedef uint64_t (*dbg_callback)(uint64_t); -void * -rust_dbg_call(dbg_callback cb, void *data) { +uint64_t +rust_dbg_call(dbg_callback cb, uint64_t data) { return cb(data); } diff --git a/tests/codegen-units/partitioning/extern-drop-glue.rs b/tests/codegen-units/partitioning/extern-drop-glue.rs index 84eb802f264b8..d3bce7b4223cc 100644 --- a/tests/codegen-units/partitioning/extern-drop-glue.rs +++ b/tests/codegen-units/partitioning/extern-drop-glue.rs @@ -1,7 +1,4 @@ -// - -// We specify incremental here because we want to test the partitioning for -//@ incremental compilation +// We specify incremental here because we want to test the partitioning for incremental compilation // We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing //@ incremental //@ compile-flags:-Zprint-mono-items=lazy diff --git a/tests/codegen-units/partitioning/extern-generic.rs b/tests/codegen-units/partitioning/extern-generic.rs index abd3918094d74..0e4b6a37f7122 100644 --- a/tests/codegen-units/partitioning/extern-generic.rs +++ b/tests/codegen-units/partitioning/extern-generic.rs @@ -1,6 +1,4 @@ -// -// We specify incremental here because we want to test the partitioning for -//@ incremental compilation +// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental //@ compile-flags:-Zprint-mono-items=eager -Zshare-generics=y diff --git a/tests/codegen-units/partitioning/incremental-merging.rs b/tests/codegen-units/partitioning/incremental-merging.rs index b44090c866a0f..6834bb2bebf5c 100644 --- a/tests/codegen-units/partitioning/incremental-merging.rs +++ b/tests/codegen-units/partitioning/incremental-merging.rs @@ -1,5 +1,4 @@ -// We specify incremental here because we want to test the partitioning for -//@ incremental compilation +// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental //@ compile-flags:-Zprint-mono-items=lazy //@ compile-flags:-Ccodegen-units=3 diff --git a/tests/codegen-units/partitioning/inlining-from-extern-crate.rs b/tests/codegen-units/partitioning/inlining-from-extern-crate.rs index 74734d3cf38a1..d021f467f1f98 100644 --- a/tests/codegen-units/partitioning/inlining-from-extern-crate.rs +++ b/tests/codegen-units/partitioning/inlining-from-extern-crate.rs @@ -1,6 +1,4 @@ -// -// We specify incremental here because we want to test the partitioning for -//@ incremental compilation +// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental //@ compile-flags:-Zprint-mono-items=lazy //@ compile-flags:-Zinline-in-all-cgus diff --git a/tests/codegen-units/partitioning/local-drop-glue.rs b/tests/codegen-units/partitioning/local-drop-glue.rs index 0974187ade0dd..5fa1df95cbc82 100644 --- a/tests/codegen-units/partitioning/local-drop-glue.rs +++ b/tests/codegen-units/partitioning/local-drop-glue.rs @@ -1,6 +1,4 @@ -// -// We specify incremental here because we want to test the partitioning for -//@ incremental compilation +// We specify incremental here because we want to test the partitioning for incremental compilation // We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing //@ incremental //@ compile-flags:-Zprint-mono-items=lazy diff --git a/tests/codegen-units/partitioning/local-generic.rs b/tests/codegen-units/partitioning/local-generic.rs index 2cfdc27ccb149..06f46b23db6ae 100644 --- a/tests/codegen-units/partitioning/local-generic.rs +++ b/tests/codegen-units/partitioning/local-generic.rs @@ -1,5 +1,4 @@ -// We specify incremental here because we want to test the partitioning for -//@ incremental compilation +// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental //@ compile-flags:-Zprint-mono-items=eager diff --git a/tests/codegen-units/partitioning/local-inlining-but-not-all.rs b/tests/codegen-units/partitioning/local-inlining-but-not-all.rs index 49a2ce7c5d9d4..2f9cbe83f1d56 100644 --- a/tests/codegen-units/partitioning/local-inlining-but-not-all.rs +++ b/tests/codegen-units/partitioning/local-inlining-but-not-all.rs @@ -1,6 +1,4 @@ -// -// We specify incremental here because we want to test the partitioning for -//@ incremental compilation +// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental //@ compile-flags:-Zprint-mono-items=lazy //@ compile-flags:-Zinline-in-all-cgus=no diff --git a/tests/codegen-units/partitioning/local-inlining.rs b/tests/codegen-units/partitioning/local-inlining.rs index 726cf2b87d268..2329a876c960f 100644 --- a/tests/codegen-units/partitioning/local-inlining.rs +++ b/tests/codegen-units/partitioning/local-inlining.rs @@ -1,6 +1,4 @@ -// -// We specify incremental here because we want to test the partitioning for -//@ incremental compilation +// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental //@ compile-flags:-Zprint-mono-items=lazy //@ compile-flags:-Zinline-in-all-cgus diff --git a/tests/codegen-units/partitioning/local-transitive-inlining.rs b/tests/codegen-units/partitioning/local-transitive-inlining.rs index 355eb6cf3954b..4ccc53aea1d12 100644 --- a/tests/codegen-units/partitioning/local-transitive-inlining.rs +++ b/tests/codegen-units/partitioning/local-transitive-inlining.rs @@ -1,6 +1,4 @@ -// -// We specify incremental here because we want to test the partitioning for -//@ incremental compilation +// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental //@ compile-flags:-Zprint-mono-items=lazy //@ compile-flags:-Zinline-in-all-cgus diff --git a/tests/codegen-units/partitioning/methods-are-with-self-type.rs b/tests/codegen-units/partitioning/methods-are-with-self-type.rs index 2e54725ff2850..3ba53334cc907 100644 --- a/tests/codegen-units/partitioning/methods-are-with-self-type.rs +++ b/tests/codegen-units/partitioning/methods-are-with-self-type.rs @@ -3,9 +3,7 @@ // much sense at the moment. //@ ignore-test -// -// We specify incremental here because we want to test the partitioning for -//@ incremental compilation +// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental //@ compile-flags:-Zprint-mono-items=lazy diff --git a/tests/codegen-units/partitioning/regular-modules.rs b/tests/codegen-units/partitioning/regular-modules.rs index 0eb0848e45446..68601975d0627 100644 --- a/tests/codegen-units/partitioning/regular-modules.rs +++ b/tests/codegen-units/partitioning/regular-modules.rs @@ -1,5 +1,4 @@ -// We specify incremental here because we want to test the partitioning for -//@ incremental compilation +// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental //@ compile-flags:-Zprint-mono-items=eager diff --git a/tests/codegen-units/partitioning/shared-generics.rs b/tests/codegen-units/partitioning/shared-generics.rs index 25ea7fab7355c..5b78794316c68 100644 --- a/tests/codegen-units/partitioning/shared-generics.rs +++ b/tests/codegen-units/partitioning/shared-generics.rs @@ -1,4 +1,3 @@ -// //@ no-prefer-dynamic // NOTE: We always compile this test with -Copt-level=0 because higher opt-levels // prevent drop-glue from participating in share-generics. diff --git a/tests/codegen-units/partitioning/statics.rs b/tests/codegen-units/partitioning/statics.rs index 9503a91b0ab4b..c7eef1f3789d9 100644 --- a/tests/codegen-units/partitioning/statics.rs +++ b/tests/codegen-units/partitioning/statics.rs @@ -1,5 +1,4 @@ -// We specify incremental here because we want to test the partitioning for -//@ incremental compilation +// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental //@ compile-flags:-Zprint-mono-items=lazy diff --git a/tests/codegen-units/partitioning/vtable-through-const.rs b/tests/codegen-units/partitioning/vtable-through-const.rs index 111b4fa1b9ac2..ca4d3822b5491 100644 --- a/tests/codegen-units/partitioning/vtable-through-const.rs +++ b/tests/codegen-units/partitioning/vtable-through-const.rs @@ -1,7 +1,4 @@ -// - -// We specify incremental here because we want to test the partitioning for -//@ incremental compilation +// We specify incremental here because we want to test the partitioning for incremental compilation //@ incremental //@ compile-flags:-Zprint-mono-items=lazy //@ compile-flags:-Zinline-in-all-cgus diff --git a/tests/codegen/debug-fndef-size.rs b/tests/codegen/debug-fndef-size.rs index 5551d2cc39cf8..27bf00adf0e54 100644 --- a/tests/codegen/debug-fndef-size.rs +++ b/tests/codegen/debug-fndef-size.rs @@ -13,6 +13,6 @@ pub fn main() { } // CHECK: %compare.dbg.spill = alloca [0 x i8], align 1 -// CHECK: call void @llvm.dbg.declare(metadata ptr %compare.dbg.spill, metadata ![[VAR:.*]], metadata !DIExpression()), !dbg !{{.*}} +// CHECK: dbg{{.}}declare({{(metadata )?}}ptr %compare.dbg.spill, {{(metadata )?}}![[VAR:.*]], {{(metadata )?}}!DIExpression() // CHECK: ![[TYPE:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "fn(&i32, &i32) -> core::cmp::Ordering", baseType: !{{.*}}, align: 1, dwarfAddressSpace: {{.*}}) // CHECK: ![[VAR]] = !DILocalVariable(name: "compare", scope: !{{.*}}, file: !{{.*}}, line: {{.*}}, type: ![[TYPE]], align: 1) diff --git a/tests/codegen/debuginfo-constant-locals.rs b/tests/codegen/debuginfo-constant-locals.rs index f607e0dd08bf9..c8f1d964722ef 100644 --- a/tests/codegen/debuginfo-constant-locals.rs +++ b/tests/codegen/debuginfo-constant-locals.rs @@ -18,8 +18,8 @@ fn foo(x: i32) { } // CHECK-LABEL: @check_it -// CHECK: call void @llvm.dbg.value(metadata i32 1, metadata ![[a_metadata:[0-9]+]], metadata !DIExpression()) -// CHECK: call void @llvm.dbg.value(metadata i32 42, metadata ![[b_metadata:[0-9]+]], metadata !DIExpression()) +// CHECK: dbg{{.}}value({{(metadata )?}}i32 1, {{(metadata )?}}![[a_metadata:[0-9]+]], {{(metadata )?}}!DIExpression() +// CHECK: dbg{{.}}value({{(metadata )?}}i32 42, {{(metadata )?}}![[b_metadata:[0-9]+]], {{(metadata )?}}!DIExpression() // CHECK: ![[a_metadata]] = !DILocalVariable(name: "a" // CHECK-SAME: line: 9 diff --git a/tests/codegen/inline-debuginfo.rs b/tests/codegen/inline-debuginfo.rs index b6ea489f99f83..f327180560ded 100644 --- a/tests/codegen/inline-debuginfo.rs +++ b/tests/codegen/inline-debuginfo.rs @@ -9,7 +9,7 @@ pub extern "C" fn callee(x: u32) -> u32 { } // CHECK-LABEL: caller -// CHECK: call void @llvm.dbg.value(metadata i32 %y, metadata !{{.*}}, metadata !DIExpression(DW_OP_constu, 3, DW_OP_minus, DW_OP_stack_value)), !dbg [[A:!.*]] +// CHECK: dbg{{.}}value({{(metadata )?}}i32 %y, {{(metadata )?}}!{{.*}}, {{(metadata )?}}!DIExpression(DW_OP_constu, 3, DW_OP_minus, DW_OP_stack_value){{.*}} [[A:![0-9]+]] // CHECK: [[A]] = !DILocation(line: {{.*}}, scope: {{.*}}, inlinedAt: {{.*}}) #[no_mangle] pub extern "C" fn caller(y: u32) -> u32 { diff --git a/tests/codegen/mir-aggregate-no-alloca.rs b/tests/codegen/mir-aggregate-no-alloca.rs new file mode 100644 index 0000000000000..a7752d714fe39 --- /dev/null +++ b/tests/codegen/mir-aggregate-no-alloca.rs @@ -0,0 +1,123 @@ +//@ compile-flags: -O -C no-prepopulate-passes -Z randomize-layout=no + +#![crate_type = "lib"] + +#[repr(transparent)] +pub struct Transparent32(u32); + +// CHECK: i32 @make_transparent(i32 noundef %x) +#[no_mangle] +pub fn make_transparent(x: u32) -> Transparent32 { + // CHECK-NOT: alloca + // CHECK: ret i32 %x + let a = Transparent32(x); + a +} + +// CHECK: i32 @make_closure(i32 noundef %x) +#[no_mangle] +pub fn make_closure(x: i32) -> impl Fn(i32) -> i32 { + // CHECK-NOT: alloca + // CHECK: ret i32 %x + move |y| x + y +} + +#[repr(transparent)] +pub struct TransparentPair((), (u16, u16), ()); + +// CHECK: { i16, i16 } @make_transparent_pair(i16 noundef %x.0, i16 noundef %x.1) +#[no_mangle] +pub fn make_transparent_pair(x: (u16, u16)) -> TransparentPair { + // CHECK-NOT: alloca + // CHECK: %[[TEMP0:.+]] = insertvalue { i16, i16 } poison, i16 %x.0, 0 + // CHECK: %[[TEMP1:.+]] = insertvalue { i16, i16 } %[[TEMP0]], i16 %x.1, 1 + // CHECK: ret { i16, i16 } %[[TEMP1]] + let a = TransparentPair((), x, ()); + a +} + +// CHECK-LABEL: { i32, i32 } @make_2_tuple(i32 noundef %x) +#[no_mangle] +pub fn make_2_tuple(x: u32) -> (u32, u32) { + // CHECK-NOT: alloca + // CHECK: %[[TEMP0:.+]] = insertvalue { i32, i32 } poison, i32 %x, 0 + // CHECK: %[[TEMP1:.+]] = insertvalue { i32, i32 } %[[TEMP0]], i32 %x, 1 + // CHECK: ret { i32, i32 } %[[TEMP1]] + let pair = (x, x); + pair +} + +// CHECK-LABEL: i8 @make_cell_of_bool(i1 noundef zeroext %b) +#[no_mangle] +pub fn make_cell_of_bool(b: bool) -> std::cell::Cell { + // CHECK: %[[BYTE:.+]] = zext i1 %b to i8 + // CHECK: ret i8 %[[BYTE]] + std::cell::Cell::new(b) +} + +// CHECK-LABLE: { i8, i16 } @make_cell_of_bool_and_short(i1 noundef zeroext %b, i16 noundef %s) +#[no_mangle] +pub fn make_cell_of_bool_and_short(b: bool, s: u16) -> std::cell::Cell<(bool, u16)> { + // CHECK-NOT: alloca + // CHECK: %[[BYTE:.+]] = zext i1 %b to i8 + // CHECK: %[[TEMP0:.+]] = insertvalue { i8, i16 } poison, i8 %[[BYTE]], 0 + // CHECK: %[[TEMP1:.+]] = insertvalue { i8, i16 } %[[TEMP0]], i16 %s, 1 + // CHECK: ret { i8, i16 } %[[TEMP1]] + std::cell::Cell::new((b, s)) +} + +// CHECK-LABEL: { i1, i1 } @make_tuple_of_bools(i1 noundef zeroext %a, i1 noundef zeroext %b) +#[no_mangle] +pub fn make_tuple_of_bools(a: bool, b: bool) -> (bool, bool) { + // CHECK-NOT: alloca + // CHECK: %[[TEMP0:.+]] = insertvalue { i1, i1 } poison, i1 %a, 0 + // CHECK: %[[TEMP1:.+]] = insertvalue { i1, i1 } %[[TEMP0]], i1 %b, 1 + // CHECK: ret { i1, i1 } %[[TEMP1]] + (a, b) +} + +pub struct Struct0(); + +// CHECK-LABEL: void @make_struct_0() +#[no_mangle] +pub fn make_struct_0() -> Struct0 { + // CHECK: ret void + let s = Struct0(); + s +} + +pub struct Struct1(i32); + +// CHECK-LABEL: i32 @make_struct_1(i32 noundef %a) +#[no_mangle] +pub fn make_struct_1(a: i32) -> Struct1 { + // CHECK: ret i32 %a + let s = Struct1(a); + s +} + +pub struct Struct2Asc(i16, i64); + +// CHECK-LABEL: { i64, i16 } @make_struct_2_asc(i16 noundef %a, i64 noundef %b) +#[no_mangle] +pub fn make_struct_2_asc(a: i16, b: i64) -> Struct2Asc { + // CHECK-NOT: alloca + // CHECK: %[[TEMP0:.+]] = insertvalue { i64, i16 } poison, i64 %b, 0 + // CHECK: %[[TEMP1:.+]] = insertvalue { i64, i16 } %[[TEMP0]], i16 %a, 1 + // CHECK: ret { i64, i16 } %[[TEMP1]] + let s = Struct2Asc(a, b); + s +} + +pub struct Struct2Desc(i64, i16); + +// CHECK-LABEL: { i64, i16 } @make_struct_2_desc(i64 noundef %a, i16 noundef %b) +#[no_mangle] +pub fn make_struct_2_desc(a: i64, b: i16) -> Struct2Desc { + // CHECK-NOT: alloca + // CHECK: %[[TEMP0:.+]] = insertvalue { i64, i16 } poison, i64 %a, 0 + // CHECK: %[[TEMP1:.+]] = insertvalue { i64, i16 } %[[TEMP0]], i16 %b, 1 + // CHECK: ret { i64, i16 } %[[TEMP1]] + let s = Struct2Desc(a, b); + s +} diff --git a/tests/codegen/option-niche-eq.rs b/tests/codegen/option-niche-eq.rs index 7b955332fd3b5..25ea5dd595c31 100644 --- a/tests/codegen/option-niche-eq.rs +++ b/tests/codegen/option-niche-eq.rs @@ -7,7 +7,7 @@ use core::cmp::Ordering; use core::ptr::NonNull; use core::num::NonZero; -// CHECK-lABEL: @non_zero_eq +// CHECK-LABEL: @non_zero_eq #[no_mangle] pub fn non_zero_eq(l: Option>, r: Option>) -> bool { // CHECK: start: @@ -16,7 +16,7 @@ pub fn non_zero_eq(l: Option>, r: Option>) -> bool { l == r } -// CHECK-lABEL: @non_zero_signed_eq +// CHECK-LABEL: @non_zero_signed_eq #[no_mangle] pub fn non_zero_signed_eq(l: Option>, r: Option>) -> bool { // CHECK: start: @@ -25,7 +25,7 @@ pub fn non_zero_signed_eq(l: Option>, r: Option>) -> b l == r } -// CHECK-lABEL: @non_null_eq +// CHECK-LABEL: @non_null_eq #[no_mangle] pub fn non_null_eq(l: Option>, r: Option>) -> bool { // CHECK: start: @@ -34,7 +34,7 @@ pub fn non_null_eq(l: Option>, r: Option>) -> bool { l == r } -// CHECK-lABEL: @ordering_eq +// CHECK-LABEL: @ordering_eq #[no_mangle] pub fn ordering_eq(l: Option, r: Option) -> bool { // CHECK: start: @@ -54,7 +54,7 @@ pub enum EnumWithNiche { G, } -// CHECK-lABEL: @niche_eq +// CHECK-LABEL: @niche_eq #[no_mangle] pub fn niche_eq(l: Option, r: Option) -> bool { // CHECK: start: @@ -64,7 +64,7 @@ pub fn niche_eq(l: Option, r: Option) -> bool { } // FIXME: This should work too -// // FIXME-CHECK-lABEL: @bool_eq +// // FIXME-CHECK-LABEL: @bool_eq // #[no_mangle] // pub fn bool_eq(l: Option, r: Option) -> bool { // // FIXME-CHECK: start: diff --git a/tests/codegen/sanitizer/no-sanitize-inlining.rs b/tests/codegen/sanitizer/no-sanitize-inlining.rs index 623bfa608ca39..d5e47884f8584 100644 --- a/tests/codegen/sanitizer/no-sanitize-inlining.rs +++ b/tests/codegen/sanitizer/no-sanitize-inlining.rs @@ -16,7 +16,7 @@ // ASAN: } // // LSAN-LABEL: define void @test -// LSAN-NO: call +// LSAN-NOT: call // LSAN: } #[no_mangle] pub fn test(n: &mut u32) { diff --git a/tests/codegen/simd/issue-120720-reduce-nan.rs b/tests/codegen/simd/issue-120720-reduce-nan.rs index 2c6098c04891f..0372582bf7f38 100644 --- a/tests/codegen/simd/issue-120720-reduce-nan.rs +++ b/tests/codegen/simd/issue-120720-reduce-nan.rs @@ -8,7 +8,7 @@ #![feature(stdarch_x86_avx512, avx512_target_feature)] use std::arch::x86_64::*; -// CHECK-label: @demo( +// CHECK-LABEL: @demo( #[no_mangle] #[target_feature(enable = "avx512f")] // Function-level target feature mismatches inhibit inlining pub unsafe fn demo() -> bool { diff --git a/tests/codegen/sroa-fragment-debuginfo.rs b/tests/codegen/sroa-fragment-debuginfo.rs index 32786d2a76a48..670ddb56540ec 100644 --- a/tests/codegen/sroa-fragment-debuginfo.rs +++ b/tests/codegen/sroa-fragment-debuginfo.rs @@ -17,9 +17,9 @@ pub fn extra(s: &[u8]) { // CHECK: %slice.dbg.spill1 = alloca [4 x i8], // CHECK: %slice.dbg.spill = alloca [16 x i8], // CHECK: %s.dbg.spill = alloca [16 x i8], -// CHECK: call void @llvm.dbg.declare(metadata ptr %s.dbg.spill, metadata ![[S_EXTRA:.*]], metadata !DIExpression()), -// CHECK: call void @llvm.dbg.declare(metadata ptr %slice.dbg.spill, metadata ![[SLICE_EXTRA:.*]], metadata !DIExpression(DW_OP_LLVM_fragment, 0, 128)), -// CHECK: call void @llvm.dbg.declare(metadata ptr %slice.dbg.spill1, metadata ![[SLICE_EXTRA]], metadata !DIExpression(DW_OP_LLVM_fragment, 128, 32)), +// CHECK: dbg{{.}}declare({{(metadata )?}}ptr %s.dbg.spill, {{(metadata )?}}![[S_EXTRA:.*]], {{(metadata )?}}!DIExpression() +// CHECK: dbg{{.}}declare({{(metadata )?}}ptr %slice.dbg.spill, {{(metadata )?}}![[SLICE_EXTRA:.*]], {{(metadata )?}}!DIExpression(DW_OP_LLVM_fragment, 0, 128) +// CHECK: dbg{{.}}declare({{(metadata )?}}ptr %slice.dbg.spill1, {{(metadata )?}}![[SLICE_EXTRA]], {{(metadata )?}}!DIExpression(DW_OP_LLVM_fragment, 128, 32) let slice = ExtraSlice { slice: s, extra: s.len() as u32 }; } @@ -36,9 +36,9 @@ pub fn zst(s: &[u8]) { // variable, so is not a fragment. In that case, the variable must have no fragment. // CHECK: void @zst( -// CHECK-NOT: call void @llvm.dbg.declare(metadata ptr %slice.dbg.spill, metadata !{}, metadata !DIExpression(DW_OP_LLVM_fragment, -// CHECK: call void @llvm.dbg.declare(metadata ptr %{{.*}}, metadata ![[SLICE_ZST:.*]], metadata !DIExpression()), -// CHECK-NOT: call void @llvm.dbg.declare(metadata ptr %{{.*}}, metadata ![[SLICE_ZST]], +// CHECK-NOT: dbg{{.}}declare({{(metadata )?}}ptr %slice.dbg.spill, {{(metadata )?}}!{}, {{(metadata )?}}!DIExpression(DW_OP_LLVM_fragment, +// CHECK: dbg{{.}}declare({{(metadata )?}}ptr %{{.*}}, {{(metadata )?}}![[SLICE_ZST:.*]], {{(metadata )?}}!DIExpression() +// CHECK-NOT: dbg{{.}}declare({{(metadata )?}}ptr %{{.*}}, {{(metadata )?}}![[SLICE_ZST]], let slice = ZstSlice { slice: s, extra: Zst }; } diff --git a/tests/coverage/branch/if-let.cov-map b/tests/coverage/branch/if-let.cov-map index c12df8d98018d..0c7d986933e7d 100644 --- a/tests/coverage/branch/if-let.cov-map +++ b/tests/coverage/branch/if-let.cov-map @@ -1,13 +1,16 @@ Function name: if_let::if_let -Raw bytes (38): 0x[01, 01, 02, 05, 09, 09, 02, 06, 01, 0c, 01, 01, 10, 02, 03, 11, 00, 12, 05, 00, 16, 00, 1b, 02, 00, 1c, 02, 06, 09, 02, 0c, 02, 06, 07, 03, 05, 01, 02] +Raw bytes (45): 0x[01, 01, 02, 05, 09, 09, 02, 07, 01, 0c, 01, 01, 10, 20, 02, 09, 03, 0c, 00, 13, 02, 00, 11, 00, 12, 05, 00, 16, 00, 1b, 02, 00, 1c, 02, 06, 09, 02, 0c, 02, 06, 07, 03, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub) -Number of file 0 mappings: 6 +Number of file 0 mappings: 7 - Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16) -- Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 18) +- Branch { true: Expression(0, Sub), false: Counter(2) } at (prev + 3, 12) to (start + 0, 19) + true = (c1 - c2) + false = c2 +- Code(Expression(0, Sub)) at (prev + 0, 17) to (start + 0, 18) = (c1 - c2) - Code(Counter(1)) at (prev + 0, 22) to (start + 0, 27) - Code(Expression(0, Sub)) at (prev + 0, 28) to (start + 2, 6) @@ -17,7 +20,7 @@ Number of file 0 mappings: 6 = (c2 + (c1 - c2)) Function name: if_let::if_let_chain -Raw bytes (52): 0x[01, 01, 04, 01, 05, 05, 09, 0f, 0d, 05, 09, 08, 01, 17, 01, 00, 33, 02, 01, 11, 00, 12, 01, 00, 16, 00, 17, 0d, 01, 15, 00, 16, 02, 00, 1a, 00, 1b, 0d, 01, 05, 03, 06, 0f, 03, 0c, 02, 06, 0b, 03, 05, 01, 02] +Raw bytes (66): 0x[01, 01, 04, 01, 05, 05, 09, 0f, 0d, 05, 09, 0a, 01, 17, 01, 00, 33, 20, 02, 05, 01, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 17, 20, 0d, 09, 01, 10, 00, 17, 0d, 00, 15, 00, 16, 02, 00, 1a, 00, 1b, 0d, 01, 05, 03, 06, 0f, 03, 0c, 02, 06, 0b, 03, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 @@ -25,12 +28,18 @@ Number of expressions: 4 - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3) - expression 3 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 8 +Number of file 0 mappings: 10 - Code(Counter(0)) at (prev + 23, 1) to (start + 0, 51) -- Code(Expression(0, Sub)) at (prev + 1, 17) to (start + 0, 18) +- Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 1, 12) to (start + 0, 19) + true = (c0 - c1) + false = c1 +- Code(Expression(0, Sub)) at (prev + 0, 17) to (start + 0, 18) = (c0 - c1) - Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23) -- Code(Counter(3)) at (prev + 1, 21) to (start + 0, 22) +- Branch { true: Counter(3), false: Counter(2) } at (prev + 1, 16) to (start + 0, 23) + true = c3 + false = c2 +- Code(Counter(3)) at (prev + 0, 21) to (start + 0, 22) - Code(Expression(0, Sub)) at (prev + 0, 26) to (start + 0, 27) = (c0 - c1) - Code(Counter(3)) at (prev + 1, 5) to (start + 3, 6) diff --git a/tests/coverage/branch/if-let.coverage b/tests/coverage/branch/if-let.coverage index f30c5d34eca17..9a3f0113f7515 100644 --- a/tests/coverage/branch/if-let.coverage +++ b/tests/coverage/branch/if-let.coverage @@ -14,6 +14,9 @@ LL| | LL| 3| if let Some(x) = input { ^2 + ------------------ + | Branch (LL:12): [True: 2, False: 1] + ------------------ LL| 2| say(x); LL| 2| } else { LL| 1| say("none"); @@ -24,8 +27,14 @@ LL| 15|fn if_let_chain(a: Option<&str>, b: Option<&str>) { LL| 15| if let Some(x) = a ^12 + ------------------ + | Branch (LL:12): [True: 12, False: 3] + ------------------ LL| 12| && let Some(y) = b ^8 + ------------------ + | Branch (LL:16): [True: 8, False: 4] + ------------------ LL| 8| { LL| 8| say(x); LL| 8| say(y); diff --git a/tests/coverage/branch/let-else.cov-map b/tests/coverage/branch/let-else.cov-map index ad987bd6bb1e9..c7f7adddbc295 100644 --- a/tests/coverage/branch/let-else.cov-map +++ b/tests/coverage/branch/let-else.cov-map @@ -1,13 +1,16 @@ Function name: let_else::let_else -Raw bytes (38): 0x[01, 01, 02, 05, 09, 09, 02, 06, 01, 0c, 01, 01, 10, 02, 03, 0e, 00, 0f, 05, 00, 13, 00, 18, 09, 01, 09, 01, 0f, 02, 04, 05, 00, 0b, 07, 01, 01, 00, 02] +Raw bytes (45): 0x[01, 01, 02, 05, 09, 09, 02, 07, 01, 0c, 01, 01, 10, 20, 02, 09, 03, 09, 00, 10, 02, 00, 0e, 00, 0f, 05, 00, 13, 00, 18, 09, 01, 09, 01, 0f, 02, 04, 05, 00, 0b, 07, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub) -Number of file 0 mappings: 6 +Number of file 0 mappings: 7 - Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16) -- Code(Expression(0, Sub)) at (prev + 3, 14) to (start + 0, 15) +- Branch { true: Expression(0, Sub), false: Counter(2) } at (prev + 3, 9) to (start + 0, 16) + true = (c1 - c2) + false = c2 +- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 15) = (c1 - c2) - Code(Counter(1)) at (prev + 0, 19) to (start + 0, 24) - Code(Counter(2)) at (prev + 1, 9) to (start + 1, 15) diff --git a/tests/coverage/branch/let-else.coverage b/tests/coverage/branch/let-else.coverage index 83730e1dfbafe..22ad8f2b0e138 100644 --- a/tests/coverage/branch/let-else.coverage +++ b/tests/coverage/branch/let-else.coverage @@ -14,6 +14,9 @@ LL| | LL| 3| let Some(x) = value else { ^2 + ------------------ + | Branch (LL:9): [True: 2, False: 1] + ------------------ LL| 1| say("none"); LL| 1| return; LL| | }; diff --git a/tests/crashes/120421.rs b/tests/crashes/120421.rs deleted file mode 100644 index b6059f3ace4fd..0000000000000 --- a/tests/crashes/120421.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #120421 -//@ compile-flags: -Zlint-mir - -#![feature(never_patterns)] - -enum Void {} - -fn main() { - let res_void: Result = Ok(true); - - for (Ok(mut _x) | Err(!)) in [res_void] {} -} diff --git a/tests/crashes/122989.rs b/tests/crashes/122989.rs deleted file mode 100644 index 70ad7d3b65c9b..0000000000000 --- a/tests/crashes/122989.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #122989 -trait Traitor = 1, const N: N<2> = N> { - fn N(&N) -> N<2> { - M - } -} - -trait N = 12> {} diff --git a/tests/crashes/123901.rs b/tests/crashes/123901.rs deleted file mode 100644 index 06722f0bf2925..0000000000000 --- a/tests/crashes/123901.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #123901 -//@ edition:2021 - -pub fn test(test: &u64, temp: &u64) { - async |check, a, b| { - temp.abs_diff(12); - }; -} diff --git a/tests/crashes/123911.rs b/tests/crashes/123911.rs deleted file mode 100644 index 1a4d6a7951281..0000000000000 --- a/tests/crashes/123911.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: #123911 - -macro_rules! m { - ($attr_path: path) => { - #[$attr_path] - fn f() {} - } -} - -m!(inline<{ - let a = CharCharFloat { a: 1 }; - let b = rustrt::rust_dbg_abi_4(a); - println!("a: {}", b.a); -}>); - -fn main() {} diff --git a/tests/crashes/123912.rs b/tests/crashes/123912.rs deleted file mode 100644 index 35216caabcdbf..0000000000000 --- a/tests/crashes/123912.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ known-bug: #123912 - -macro_rules! m { - ($attr_path: path) => { - #[$attr_path] - fn f() {} - } -} - -m!(inline<{ - let a = CharCharFloat { a: 1 }; - println!("a: {}", a); -}>); - -fn main() {} diff --git a/tests/crashes/124436.rs b/tests/crashes/124436.rs new file mode 100644 index 0000000000000..aed830e8f0e4b --- /dev/null +++ b/tests/crashes/124436.rs @@ -0,0 +1,7 @@ +//@ known-bug: rust-lang/rust#124436 +//@ compile-flags: -Zdump-mir=all -Zpolymorphize=on + +pub trait TraitCat {} +pub trait TraitDog {} + +pub fn gamma(t: [TraitDog; 32]) {} diff --git a/tests/crashes/124440.rs b/tests/crashes/124440.rs new file mode 100644 index 0000000000000..431c4e444f10a --- /dev/null +++ b/tests/crashes/124440.rs @@ -0,0 +1,23 @@ +//@ known-bug: rust-lang/rust#124440 + +#![allow(warnings)] + +trait Foo {} + +impl Foo for F where F: FnMut(&()) {} + +struct Bar { + f: F, +} + +impl Foo for Bar where F: Foo {} + +fn assert_foo(_: F) +where + Bar: Foo, +{ +} + +fn main() { + assert_foo(|_| ()); +} diff --git a/tests/crashes/124464.rs b/tests/crashes/124464.rs new file mode 100644 index 0000000000000..471479f5cf1b6 --- /dev/null +++ b/tests/crashes/124464.rs @@ -0,0 +1,17 @@ +//@ known-bug: rust-lang/rust #124464 +enum TestOption { + TestSome(T), + TestSome(T), +} + +pub struct Request { + bar: TestOption, + bar: u8, +} + +fn default_instance() -> &'static Request { + static instance: Request = Request { bar: 17 }; + &instance +} + +pub fn main() {} diff --git a/tests/crashes/124490.rs b/tests/crashes/124490.rs new file mode 100644 index 0000000000000..9f605c32cf261 --- /dev/null +++ b/tests/crashes/124490.rs @@ -0,0 +1,16 @@ +//@ known-bug: rust-lang/rust#124490 +use io::{self as std}; +use std::collections::{self as io}; + +mod a { + pub mod b { + pub mod c {} + } +} + +use a::*; + +use b::c; +use c as b; + +fn main() {} diff --git a/tests/crashes/124552.rs b/tests/crashes/124552.rs new file mode 100644 index 0000000000000..5320ce2784305 --- /dev/null +++ b/tests/crashes/124552.rs @@ -0,0 +1,12 @@ +//@ known-bug: rust-lang/rust#124552 + +struct B; + +struct Foo { + b: u32, + b: B, +} + +static BAR: Foo = Foo { b: B }; + +fn main() {} diff --git a/tests/crashes/124563.rs b/tests/crashes/124563.rs new file mode 100644 index 0000000000000..b082739af53d9 --- /dev/null +++ b/tests/crashes/124563.rs @@ -0,0 +1,46 @@ +//@ known-bug: rust-lang/rust#124563 + +use std::marker::PhantomData; + +pub trait Trait {} + +pub trait Foo { + type Trait: Trait; + type Bar: Bar; + fn foo(&mut self); +} + +pub struct FooImpl<'a, 'b, A: Trait>(PhantomData<&'a &'b A>); + +impl<'a, 'b, T> Foo for FooImpl<'a, 'b, T> +where + T: Trait, +{ + type Trait = T; + type Bar = BarImpl<'a, 'b, T>; + + fn foo(&mut self) { + self.enter_scope(|ctx| { + BarImpl(ctx); + }); + } +} + +impl<'a, 'b, T> FooImpl<'a, 'b, T> +where + T: Trait, +{ + fn enter_scope(&mut self, _scope: impl FnOnce(&mut Self)) {} +} +pub trait Bar { + type Foo: Foo; +} + +pub struct BarImpl<'a, 'b, T: Trait>(&'b mut FooImpl<'a, 'b, T>); + +impl<'a, 'b, T> Bar for BarImpl<'a, 'b, T> +where + T: Trait, +{ + type Foo = FooImpl<'a, 'b, T>; +} diff --git a/tests/crashes/124583.rs b/tests/crashes/124583.rs new file mode 100644 index 0000000000000..ffd9d7521add2 --- /dev/null +++ b/tests/crashes/124583.rs @@ -0,0 +1,5 @@ +//@ known-bug: rust-lang/rust#124583 + +fn main() { + let _ = -(-0.0f16); +} diff --git a/tests/crashes/124751.rs b/tests/crashes/124751.rs new file mode 100644 index 0000000000000..f15e39965d3ed --- /dev/null +++ b/tests/crashes/124751.rs @@ -0,0 +1,8 @@ +//@ known-bug: rust-lang/rust#124751 +//@ compile-flags: -Zunstable-options --edition=2024 + +#![feature(gen_blocks)] + +fn main() { + let _ = async gen || {}; +} diff --git a/tests/debuginfo/borrowed-enum.rs b/tests/debuginfo/borrowed-enum.rs index 39883ffd0b6ab..fc2ab62a21c49 100644 --- a/tests/debuginfo/borrowed-enum.rs +++ b/tests/debuginfo/borrowed-enum.rs @@ -1,6 +1,6 @@ // Require a gdb or lldb that can read DW_TAG_variant_part. //@ min-gdb-version: 8.2 -//@ needs-rust-lldb +//@ min-lldb-version: 1800 //@ compile-flags:-g @@ -23,10 +23,13 @@ // lldb-command:run // lldb-command:v *the_a_ref +// lldbg-check:(borrowed_enum::ABC) *the_a_ref = { value = { x = 0 y = 8970181431921507452 } $discr$ = 0 } // lldbr-check:(borrowed_enum::ABC::TheA) *the_a_ref = TheA { TheA: 0, TheB: 8970181431921507452 } // lldb-command:v *the_b_ref +// lldbg-check:(borrowed_enum::ABC) *the_b_ref = { value = { 0 = 0 1 = 286331153 2 = 286331153 } $discr$ = 1 } // lldbr-check:(borrowed_enum::ABC::TheB) *the_b_ref = { = 0 = 286331153 = 286331153 } // lldb-command:v *univariant_ref +// lldbg-check:(borrowed_enum::Univariant) *univariant_ref = { value = { 0 = 4820353753753434 } } // lldbr-check:(borrowed_enum::Univariant) *univariant_ref = { TheOnlyCase = { = 4820353753753434 } } #![allow(unused_variables)] diff --git a/tests/debuginfo/coroutine-objects.rs b/tests/debuginfo/coroutine-objects.rs index e13f20455a864..746b7e40eda53 100644 --- a/tests/debuginfo/coroutine-objects.rs +++ b/tests/debuginfo/coroutine-objects.rs @@ -1,8 +1,9 @@ // Require a gdb that can read DW_TAG_variant_part. //@ min-gdb-version: 8.2 +//@ min-lldb-version: 1800 -// LLDB without native Rust support cannot read DW_TAG_variant_part, -// so it prints nothing for coroutines. But those tests are kept to +// LLDB (18.1+) now supports DW_TAG_variant_part, but there is some bug in either compiler or LLDB +// with memory layout of discriminant for this particular enum // ensure that LLDB won't crash at least (like #57822). //@ compile-flags:-g @@ -26,16 +27,7 @@ // lldb-command:run // lldb-command:v b -// lldbg-check:(coroutine_objects::main::{coroutine_env#0}) b = -// lldb-command:continue -// lldb-command:v b -// lldbg-check:(coroutine_objects::main::{coroutine_env#0}) b = -// lldb-command:continue -// lldb-command:v b -// lldbg-check:(coroutine_objects::main::{coroutine_env#0}) b = -// lldb-command:continue -// lldb-command:v b -// lldbg-check:(coroutine_objects::main::{coroutine_env#0}) b = +// lldb-check:(coroutine_objects::main::{coroutine_env#0}) b = { value = { _ref__a = 0x[...] } $discr$ = [...] } // === CDB TESTS =================================================================================== diff --git a/tests/debuginfo/enum-thinlto.rs b/tests/debuginfo/enum-thinlto.rs index f3f177589318c..42a0d1e28f8e5 100644 --- a/tests/debuginfo/enum-thinlto.rs +++ b/tests/debuginfo/enum-thinlto.rs @@ -1,6 +1,6 @@ // Require a gdb that can read DW_TAG_variant_part. //@ min-gdb-version: 8.2 - +//@ min-lldb-version: 1800 //@ compile-flags:-g -Z thinlto // === GDB TESTS =================================================================================== @@ -15,7 +15,7 @@ // lldb-command:run // lldb-command:v *abc -// lldbg-check:(enum_thinlto::ABC) *abc = +// lldbg-check:(enum_thinlto::ABC) *abc = { value = { x = 0 y = 8970181431921507452 } $discr$ = 0 } // lldbr-check:(enum_thinlto::ABC) *abc = (x = 0, y = 8970181431921507452) #![allow(unused_variables)] diff --git a/tests/debuginfo/issue-57822.rs b/tests/debuginfo/issue-57822.rs index 995779a6a9ca8..cadd9b542e9cb 100644 --- a/tests/debuginfo/issue-57822.rs +++ b/tests/debuginfo/issue-57822.rs @@ -3,7 +3,7 @@ // Require a gdb that can read DW_TAG_variant_part. //@ min-gdb-version: 8.2 - +//@ min-lldb-version: 1800 //@ compile-flags:-g // === GDB TESTS =================================================================================== @@ -24,7 +24,7 @@ // lldbg-check:(issue_57822::main::{closure_env#1}) g = { f = { x = 1 } } // lldb-command:v b -// lldbg-check:(issue_57822::main::{coroutine_env#3}) b = +// lldbg-check:(issue_57822::main::{coroutine_env#3}) b = { value = { a = { value = { y = 2 } $discr$ = '\x02' } } $discr$ = '\x02' } #![feature(omit_gdb_pretty_printer_section, coroutines, coroutine_trait, stmt_expr_attributes)] #![omit_gdb_pretty_printer_section] diff --git a/tests/debuginfo/msvc-pretty-enums.rs b/tests/debuginfo/msvc-pretty-enums.rs index 0293ec0ec3975..a6032cc864235 100644 --- a/tests/debuginfo/msvc-pretty-enums.rs +++ b/tests/debuginfo/msvc-pretty-enums.rs @@ -1,6 +1,80 @@ -//@ only-cdb +//@ min-lldb-version: 1800 +//@ ignore-gdb //@ compile-flags:-g -// + +// === LLDB TESTS ================================================================================== +// lldb-command:run + +// lldb-command:v a +// lldbg-check:(core::option::Option) a = { value = { 0 = Low } } + +// lldb-command:v b +// lldbg-check:(core::option::Option) b = { value = $discr$ = '\x01' } + +// lldb-command:v c +// lldbg-check:(msvc_pretty_enums::NicheLayoutEnum) c = { value = $discr$ = '\x11' } + +// lldb-command:v d +// lldbg-check:(msvc_pretty_enums::NicheLayoutEnum) d = { value = { my_data = High } } + +// lldb-command:v e +// lldbg-check:(msvc_pretty_enums::NicheLayoutEnum) e = { value = $discr$ = '\x13' } + +// lldb-command:v h +// lldbg-check:(core::option::Option) h = { value = { 0 = 12 } $discr$ = 1 } + +// lldb-command:v i +// lldbg-check:(core::option::Option) i = { value = $discr$ = 0 } + +// lldb-command:v j +// lldbg-check:(msvc_pretty_enums::CStyleEnum) j = High + +// lldb-command:v k +// lldbg-check:(core::option::Option) k = { value = { 0 = "IAMA optional string!" { vec = size=21 { [0] = 'I' [1] = 'A' [2] = 'M' [3] = 'A' [4] = ' ' [5] = 'o' [6] = 'p' [7] = 't' [8] = 'i' [9] = 'o' [10] = 'n' [11] = 'a' [12] = 'l' [13] = ' ' [14] = 's' [15] = 't' [16] = 'r' [17] = 'i' [18] = 'n' [19] = 'g' [20] = '!' } } } } + +// lldb-command:v l +// lldbg-check:(core::result::Result) l = { value = { 0 = {} } } + +// lldb-command:v niche128_some +// lldbg-check:(core::option::Option>) niche128_some = { value = $discr$ = 123456 } + +// lldb-command:v niche128_none +// lldbg-check:(core::option::Option>) niche128_none = { value = $discr$ = 0 } + +// lldb-command:v wrapping_niche128_untagged +// lldbg-check:(msvc_pretty_enums::Wrapping128Niche) wrapping_niche128_untagged = { value = { 0 = { 0 = 340282366920938463463374607431768211454 } } } + +// lldb-command:v wrapping_niche128_none1 +// lldbg-check:(msvc_pretty_enums::Wrapping128Niche) wrapping_niche128_none1 = { value = { 0 = { 0 = 2 } } } + +// lldb-command:v direct_tag_128_a +// lldbg-check:(msvc_pretty_enums::DirectTag128) direct_tag_128_a = { value = { 0 = 42 } $discr$ = 0 } + +// lldb-command:v direct_tag_128_b +// lldbg-check:(msvc_pretty_enums::DirectTag128) direct_tag_128_b = { value = { 0 = 137 } $discr$ = 1 } + +// &u32 is incorrectly formatted and LLDB thinks it's a char* so skipping niche_w_fields_1_some + +// lldb-command:v niche_w_fields_1_none +// lldbg-check:(msvc_pretty_enums::NicheLayoutWithFields1) niche_w_fields_1_none = { value = { 0 = 99 } $discr$ = 1 } + +// lldb-command:v niche_w_fields_2_some +// lldbg-check:(msvc_pretty_enums::NicheLayoutWithFields2) niche_w_fields_2_some = { value = { 0 = 800 { __0 = { 0 = 800 } } 1 = 900 } $discr$ = 0 } + +// lldb-command:v niche_w_fields_3_some +// lldbg-check:(msvc_pretty_enums::NicheLayoutWithFields3) niche_w_fields_3_some = { value = { 0 = '\x89' 1 = true } } + +// lldb-command:v niche_w_fields_3_niche3 +// lldbg-check:(msvc_pretty_enums::NicheLayoutWithFields3) niche_w_fields_3_niche3 = { value = { 0 = '"' } $discr$ = '\x04' } + +// lldb-command:v arbitrary_discr1 +// lldbg-check:(msvc_pretty_enums::ArbitraryDiscr) arbitrary_discr1 = { value = { 0 = 1234 } $discr$ = 1000 } + +// lldb-command:v arbitrary_discr2 +// lldbg-check:(msvc_pretty_enums::ArbitraryDiscr) arbitrary_discr2 = { value = { 0 = 5678 } $discr$ = 5000000 } + +// === CDB TESTS ================================================================================== + // cdb-command: g // // cdb-command: dx a diff --git a/tests/debuginfo/struct-style-enum.rs b/tests/debuginfo/struct-style-enum.rs index 517b76c14120b..42368017cae69 100644 --- a/tests/debuginfo/struct-style-enum.rs +++ b/tests/debuginfo/struct-style-enum.rs @@ -1,7 +1,6 @@ // Require a gdb or lldb that can read DW_TAG_variant_part. //@ min-gdb-version: 8.2 -//@ needs-rust-lldb - +//@ min-lldb-version: 1800 //@ compile-flags:-g // === GDB TESTS =================================================================================== @@ -27,15 +26,19 @@ // lldb-command:run // lldb-command:v case1 +// lldbg-check:(struct_style_enum::Regular) case1 = { value = { a = 0 b = 31868 c = 31868 d = 31868 e = 31868 } $discr$ = 0 } // lldbr-check:(struct_style_enum::Regular::Case1) case1 = { a = 0 b = 31868 c = 31868 d = 31868 e = 31868 } // lldb-command:v case2 +// lldbg-check:(struct_style_enum::Regular) case2 = { value = { a = 0 b = 286331153 c = 286331153 } $discr$ = 1 } // lldbr-check:(struct_style_enum::Regular::Case2) case2 = Case2 { Case1: 0, Case2: 286331153, Case3: 286331153 } // lldb-command:v case3 +// lldbg-check:(struct_style_enum::Regular) case3 = { value = { a = 0 b = 6438275382588823897 } $discr$ = 2 } // lldbr-check:(struct_style_enum::Regular::Case3) case3 = Case3 { Case1: 0, Case2: 6438275382588823897 } // lldb-command:v univariant +// lldbg-check:(struct_style_enum::Univariant) univariant = { value = { a = -1 } } // lldbr-check:(struct_style_enum::Univariant) univariant = Univariant { TheOnlyCase: TheOnlyCase { a: -1 } } #![allow(unused_variables)] diff --git a/tests/debuginfo/tuple-style-enum.rs b/tests/debuginfo/tuple-style-enum.rs index 883aa658eb2c7..3de4ecb128494 100644 --- a/tests/debuginfo/tuple-style-enum.rs +++ b/tests/debuginfo/tuple-style-enum.rs @@ -1,6 +1,6 @@ // Require a gdb or lldb that can read DW_TAG_variant_part. //@ min-gdb-version: 8.2 -//@ needs-rust-lldb +//@ min-lldb-version: 1800 //@ compile-flags:-g @@ -27,15 +27,19 @@ // lldb-command:run // lldb-command:v case1 +// lldbg-check:(tuple_style_enum::Regular) case1 = { value = { 0 = 0 1 = 31868 2 = 31868 3 = 31868 4 = 31868 } $discr$ = 0 } // lldbr-check:(tuple_style_enum::Regular::Case1) case1 = { = 0 = 31868 = 31868 = 31868 = 31868 } // lldb-command:v case2 +// lldbg-check:(tuple_style_enum::Regular) case2 = { value = { 0 = 0 1 = 286331153 2 = 286331153 } $discr$ = 1 } // lldbr-check:(tuple_style_enum::Regular::Case2) case2 = Case2 { Case1: 0, Case2: 286331153, Case3: 286331153 } // lldb-command:v case3 +// lldbg-check:(tuple_style_enum::Regular) case3 = { value = { 0 = 0 1 = 6438275382588823897 } $discr$ = 2 } // lldbr-check:(tuple_style_enum::Regular::Case3) case3 = Case3 { Case1: 0, Case2: 6438275382588823897 } // lldb-command:v univariant +// lldbg-check:(tuple_style_enum::Univariant) univariant = { value = { 0 = -1 } } // lldbr-check:(tuple_style_enum::Univariant) univariant = { TheOnlyCase = { = -1 } } #![allow(unused_variables)] diff --git a/tests/debuginfo/unique-enum.rs b/tests/debuginfo/unique-enum.rs index b3879468e0a98..514c7c50812c6 100644 --- a/tests/debuginfo/unique-enum.rs +++ b/tests/debuginfo/unique-enum.rs @@ -1,6 +1,6 @@ // Require a gdb or lldb that can read DW_TAG_variant_part. //@ min-gdb-version: 8.2 -//@ needs-rust-lldb +//@ min-lldb-version: 1800 //@ compile-flags:-g @@ -23,12 +23,15 @@ // lldb-command:run // lldb-command:v *the_a +// lldbg-check:(unique_enum::ABC) *the_a = { value = { x = 0 y = 8970181431921507452 } $discr$ = 0 } // lldbr-check:(unique_enum::ABC::TheA) *the_a = TheA { TheA: 0, TheB: 8970181431921507452 } // lldb-command:v *the_b +// lldbg-check:(unique_enum::ABC) *the_b = { value = { 0 = 0 1 = 286331153 2 = 286331153 } $discr$ = 1 } // lldbr-check:(unique_enum::ABC::TheB) *the_b = { = 0 = 286331153 = 286331153 } // lldb-command:v *univariant +// lldbg-check:(unique_enum::Univariant) *univariant = { value = { 0 = 123234 } } // lldbr-check:(unique_enum::Univariant) *univariant = { TheOnlyCase = { = 123234 } } #![allow(unused_variables)] diff --git a/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir new file mode 100644 index 0000000000000..78356a90743a6 --- /dev/null +++ b/tests/mir-opt/building/match/never_patterns.opt1.SimplifyCfg-initial.after.mir @@ -0,0 +1,41 @@ +// MIR for `opt1` after SimplifyCfg-initial + +fn opt1(_1: &Result) -> &u32 { + debug res => _1; + let mut _0: &u32; + let mut _2: isize; + let _3: &u32; + let mut _4: !; + let mut _5: (); + scope 1 { + debug x => _3; + } + + bb0: { + PlaceMention(_1); + _2 = discriminant((*_1)); + switchInt(move _2) -> [0: bb2, 1: bb3, otherwise: bb1]; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb2: { + falseEdge -> [real: bb4, imaginary: bb3]; + } + + bb3: { + FakeRead(ForMatchedPlace(None), (((*_1) as Err).0: Void)); + unreachable; + } + + bb4: { + StorageLive(_3); + _3 = &(((*_1) as Ok).0: u32); + _0 = &(*_3); + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/building/match/never_patterns.opt2.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/never_patterns.opt2.SimplifyCfg-initial.after.mir new file mode 100644 index 0000000000000..979fbb2860dcb --- /dev/null +++ b/tests/mir-opt/building/match/never_patterns.opt2.SimplifyCfg-initial.after.mir @@ -0,0 +1,35 @@ +// MIR for `opt2` after SimplifyCfg-initial + +fn opt2(_1: &Result) -> &u32 { + debug res => _1; + let mut _0: &u32; + let mut _2: isize; + let _3: &u32; + scope 1 { + debug x => _3; + } + + bb0: { + PlaceMention(_1); + _2 = discriminant((*_1)); + switchInt(move _2) -> [0: bb2, 1: bb3, otherwise: bb1]; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb2: { + StorageLive(_3); + _3 = &(((*_1) as Ok).0: u32); + _0 = &(*_3); + StorageDead(_3); + return; + } + + bb3: { + FakeRead(ForMatchedPlace(None), (((*_1) as Err).0: Void)); + unreachable; + } +} diff --git a/tests/mir-opt/building/match/never_patterns.opt3.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/never_patterns.opt3.SimplifyCfg-initial.after.mir new file mode 100644 index 0000000000000..93ebe600b3ff7 --- /dev/null +++ b/tests/mir-opt/building/match/never_patterns.opt3.SimplifyCfg-initial.after.mir @@ -0,0 +1,35 @@ +// MIR for `opt3` after SimplifyCfg-initial + +fn opt3(_1: &Result) -> &u32 { + debug res => _1; + let mut _0: &u32; + let mut _2: isize; + let _3: &u32; + scope 1 { + debug x => _3; + } + + bb0: { + PlaceMention(_1); + _2 = discriminant((*_1)); + switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1]; + } + + bb1: { + FakeRead(ForMatchedPlace(None), _1); + unreachable; + } + + bb2: { + FakeRead(ForMatchedPlace(None), (((*_1) as Err).0: Void)); + unreachable; + } + + bb3: { + StorageLive(_3); + _3 = &(((*_1) as Ok).0: u32); + _0 = &(*_3); + StorageDead(_3); + return; + } +} diff --git a/tests/mir-opt/building/match/never_patterns.rs b/tests/mir-opt/building/match/never_patterns.rs new file mode 100644 index 0000000000000..8b52440da4c3d --- /dev/null +++ b/tests/mir-opt/building/match/never_patterns.rs @@ -0,0 +1,44 @@ +#![feature(never_patterns)] +#![allow(incomplete_features)] + +enum Void {} + +// EMIT_MIR never_patterns.opt1.SimplifyCfg-initial.after.mir +fn opt1(res: &Result) -> &u32 { + // CHECK-LABEL: fn opt1( + // CHECK: bb0: { + // CHECK-NOT: {{bb.*}}: { + // CHECK: return; + match res { + Ok(x) => x, + Err(!), + } +} + +// EMIT_MIR never_patterns.opt2.SimplifyCfg-initial.after.mir +fn opt2(res: &Result) -> &u32 { + // CHECK-LABEL: fn opt2( + // CHECK: bb0: { + // CHECK-NOT: {{bb.*}}: { + // CHECK: return; + match res { + Ok(x) | Err(!) => x, + } +} + +// EMIT_MIR never_patterns.opt3.SimplifyCfg-initial.after.mir +fn opt3(res: &Result) -> &u32 { + // CHECK-LABEL: fn opt3( + // CHECK: bb0: { + // CHECK-NOT: {{bb.*}}: { + // CHECK: return; + match res { + Err(!) | Ok(x) => x, + } +} + +fn main() { + assert_eq!(opt1(&Ok(0)), &0); + assert_eq!(opt2(&Ok(0)), &0); + assert_eq!(opt3(&Ok(0)), &0); +} diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff index 2a36ccaab110a..df873600577a3 100644 --- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff @@ -11,10 +11,28 @@ + scope 1 (inlined std::ptr::drop_in_place::> - shim(Some(Vec))) { + let mut _6: &mut std::vec::Vec; + let mut _7: (); ++ scope 2 (inlined as Drop>::drop) { ++ let mut _8: *mut [A]; ++ let mut _9: *mut A; ++ let mut _10: usize; ++ scope 3 (inlined Vec::::as_mut_ptr) { ++ let mut _11: &alloc::raw_vec::RawVec; ++ scope 4 (inlined alloc::raw_vec::RawVec::::ptr) { ++ let mut _13: std::ptr::NonNull; ++ scope 5 (inlined Unique::::as_ptr) { ++ scope 6 (inlined NonNull::::as_ptr) { ++ let mut _12: *const A; ++ } ++ } ++ } ++ } ++ scope 7 (inlined slice_from_raw_parts_mut::) { ++ } ++ } + } -+ scope 2 (inlined std::ptr::drop_in_place::> - shim(Some(Option))) { -+ let mut _8: isize; -+ let mut _9: isize; ++ scope 8 (inlined std::ptr::drop_in_place::> - shim(Some(Option))) { ++ let mut _14: isize; ++ let mut _15: isize; + } bb0: { @@ -25,7 +43,24 @@ + StorageLive(_6); + StorageLive(_7); + _6 = &mut (*_4); -+ _7 = as Drop>::drop(move _6) -> [return: bb2, unwind unreachable]; ++ StorageLive(_8); ++ StorageLive(_9); ++ StorageLive(_11); ++ _11 = &((*_6).0: alloc::raw_vec::RawVec); ++ StorageLive(_13); ++ _13 = ((((*_6).0: alloc::raw_vec::RawVec).0: std::ptr::Unique).0: std::ptr::NonNull); ++ StorageLive(_12); ++ _12 = (_13.0: *const A); ++ _9 = move _12 as *mut A (PtrToPtr); ++ StorageDead(_12); ++ StorageDead(_13); ++ StorageDead(_11); ++ StorageLive(_10); ++ _10 = ((*_6).1: usize); ++ _8 = *mut [A] from (_9, _10); ++ StorageDead(_10); ++ StorageDead(_9); ++ _7 = std::ptr::drop_in_place::<[A]>(move _8) -> [return: bb2, unwind unreachable]; } bb1: { @@ -36,19 +71,20 @@ StorageLive(_5); _5 = _2; - _0 = std::ptr::drop_in_place::>(move _5) -> [return: bb2, unwind unreachable]; -+ StorageLive(_8); -+ StorageLive(_9); -+ _8 = discriminant((*_5)); -+ switchInt(move _8) -> [0: bb3, otherwise: bb4]; ++ StorageLive(_14); ++ StorageLive(_15); ++ _14 = discriminant((*_5)); ++ switchInt(move _14) -> [0: bb3, otherwise: bb4]; } bb2: { ++ StorageDead(_8); + drop(((*_4).0: alloc::raw_vec::RawVec)) -> [return: bb1, unwind unreachable]; + } + + bb3: { -+ StorageDead(_9); -+ StorageDead(_8); ++ StorageDead(_15); ++ StorageDead(_14); StorageDead(_5); return; + } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index ef3f4a2172005..62fe1a8685780 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -4,20 +4,47 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug slice => _1; debug index => _2; let mut _0: &mut [u32]; + let mut _3: usize; + let mut _4: usize; scope 1 (inlined core::slice::::get_unchecked_mut::>) { - let mut _3: *mut [u32]; - let mut _4: *mut [u32]; + let mut _5: *mut [u32]; + let mut _9: *mut [u32]; + scope 2 (inlined as SliceIndex<[u32]>>::get_unchecked_mut) { + let _6: usize; + let mut _7: *mut u32; + let mut _8: *mut u32; + scope 3 { + scope 6 (inlined std::ptr::mut_ptr::::as_mut_ptr) { + } + scope 7 (inlined std::ptr::mut_ptr::::add) { + } + scope 8 (inlined slice_from_raw_parts_mut::) { + } + } + scope 4 (inlined std::ptr::mut_ptr::::len) { + scope 5 (inlined std::ptr::metadata::<[u32]>) { + } + } + } } bb0: { - StorageLive(_3); - _3 = &raw mut (*_1); - _4 = as SliceIndex<[u32]>>::get_unchecked_mut(move _2, move _3) -> [return: bb1, unwind unreachable]; - } - - bb1: { - StorageDead(_3); - _0 = &mut (*_4); + _3 = move (_2.0: usize); + _4 = move (_2.1: usize); + StorageLive(_5); + _5 = &raw mut (*_1); + StorageLive(_6); + _6 = SubUnchecked(_4, _3); + StorageLive(_8); + StorageLive(_7); + _7 = _5 as *mut u32 (PtrToPtr); + _8 = Offset(_7, _3); + StorageDead(_7); + _9 = *mut [u32] from (_8, _6); + StorageDead(_8); + StorageDead(_6); + StorageDead(_5); + _0 = &mut (*_9); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 9e93a43ac725b..62fe1a8685780 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -4,20 +4,47 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug slice => _1; debug index => _2; let mut _0: &mut [u32]; + let mut _3: usize; + let mut _4: usize; scope 1 (inlined core::slice::::get_unchecked_mut::>) { - let mut _3: *mut [u32]; - let mut _4: *mut [u32]; + let mut _5: *mut [u32]; + let mut _9: *mut [u32]; + scope 2 (inlined as SliceIndex<[u32]>>::get_unchecked_mut) { + let _6: usize; + let mut _7: *mut u32; + let mut _8: *mut u32; + scope 3 { + scope 6 (inlined std::ptr::mut_ptr::::as_mut_ptr) { + } + scope 7 (inlined std::ptr::mut_ptr::::add) { + } + scope 8 (inlined slice_from_raw_parts_mut::) { + } + } + scope 4 (inlined std::ptr::mut_ptr::::len) { + scope 5 (inlined std::ptr::metadata::<[u32]>) { + } + } + } } bb0: { - StorageLive(_3); - _3 = &raw mut (*_1); - _4 = as SliceIndex<[u32]>>::get_unchecked_mut(move _2, move _3) -> [return: bb1, unwind continue]; - } - - bb1: { - StorageDead(_3); - _0 = &mut (*_4); + _3 = move (_2.0: usize); + _4 = move (_2.1: usize); + StorageLive(_5); + _5 = &raw mut (*_1); + StorageLive(_6); + _6 = SubUnchecked(_4, _3); + StorageLive(_8); + StorageLive(_7); + _7 = _5 as *mut u32 (PtrToPtr); + _8 = Offset(_7, _3); + StorageDead(_7); + _9 = *mut [u32] from (_8, _6); + StorageDead(_8); + StorageDead(_6); + StorageDead(_5); + _0 = &mut (*_9); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir index 018ff6c357d17..000432ccca7de 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir @@ -17,11 +17,6 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - scope 7 (inlined std::ptr::const_ptr::::add) { } scope 8 (inlined slice_from_raw_parts::) { - let mut _8: *const (); - scope 9 (inlined std::ptr::const_ptr::::cast::<()>) { - } - scope 10 (inlined std::ptr::from_raw_parts::<[u32]>) { - } } } scope 4 (inlined std::ptr::const_ptr::::len) { @@ -41,10 +36,7 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - _6 = _1 as *const u32 (PtrToPtr); _7 = Offset(_6, _3); StorageDead(_6); - StorageLive(_8); - _8 = _7 as *const () (PtrToPtr); - _0 = *const [u32] from (_8, _5); - StorageDead(_8); + _0 = *const [u32] from (_7, _5); StorageDead(_7); StorageDead(_5); return; diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir index 018ff6c357d17..000432ccca7de 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir @@ -17,11 +17,6 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - scope 7 (inlined std::ptr::const_ptr::::add) { } scope 8 (inlined slice_from_raw_parts::) { - let mut _8: *const (); - scope 9 (inlined std::ptr::const_ptr::::cast::<()>) { - } - scope 10 (inlined std::ptr::from_raw_parts::<[u32]>) { - } } } scope 4 (inlined std::ptr::const_ptr::::len) { @@ -41,10 +36,7 @@ fn slice_ptr_get_unchecked_range(_1: *const [u32], _2: std::ops::Range) - _6 = _1 as *const u32 (PtrToPtr); _7 = Offset(_6, _3); StorageDead(_6); - StorageLive(_8); - _8 = _7 as *const () (PtrToPtr); - _0 = *const [u32] from (_8, _5); - StorageDead(_8); + _0 = *const [u32] from (_7, _5); StorageDead(_7); StorageDead(_5); return; diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index 18728d543ad8b..eabecaed05178 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir @@ -25,7 +25,7 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { scope 6 (inlined std::slice::from_raw_parts::<'_, u8>) { debug data => _4; debug len => _5; - let _7: *const [u8]; + let _6: *const [u8]; scope 7 (inlined core::ub_checks::check_language_ub) { scope 8 (inlined core::ub_checks::check_language_ub::runtime) { } @@ -37,14 +37,6 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { scope 11 (inlined slice_from_raw_parts::) { debug data => _4; debug len => _5; - let mut _6: *const (); - scope 12 (inlined std::ptr::const_ptr::::cast::<()>) { - debug self => _4; - } - scope 13 (inlined std::ptr::from_raw_parts::<[u8]>) { - debug data_pointer => _6; - debug metadata => _5; - } } } } @@ -60,13 +52,10 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { StorageDead(_2); StorageLive(_5); _5 = ((*_1).1: usize); - StorageLive(_6); - _6 = _4 as *const () (PtrToPtr); - _7 = *const [u8] from (_6, _5); - StorageDead(_6); + _6 = *const [u8] from (_4, _5); StorageDead(_5); StorageDead(_4); - _0 = &(*_7); + _0 = &(*_6); return; } } diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index 18728d543ad8b..eabecaed05178 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir @@ -25,7 +25,7 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { scope 6 (inlined std::slice::from_raw_parts::<'_, u8>) { debug data => _4; debug len => _5; - let _7: *const [u8]; + let _6: *const [u8]; scope 7 (inlined core::ub_checks::check_language_ub) { scope 8 (inlined core::ub_checks::check_language_ub::runtime) { } @@ -37,14 +37,6 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { scope 11 (inlined slice_from_raw_parts::) { debug data => _4; debug len => _5; - let mut _6: *const (); - scope 12 (inlined std::ptr::const_ptr::::cast::<()>) { - debug self => _4; - } - scope 13 (inlined std::ptr::from_raw_parts::<[u8]>) { - debug data_pointer => _6; - debug metadata => _5; - } } } } @@ -60,13 +52,10 @@ fn vec_deref_to_slice(_1: &Vec) -> &[u8] { StorageDead(_2); StorageLive(_5); _5 = ((*_1).1: usize); - StorageLive(_6); - _6 = _4 as *const () (PtrToPtr); - _7 = *const [u8] from (_6, _5); - StorageDead(_6); + _6 = *const [u8] from (_4, _5); StorageDead(_5); StorageDead(_4); - _0 = &(*_7); + _0 = &(*_6); return; } } diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs index 4b7ce4e57d57c..1bdb634757120 100644 --- a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs +++ b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs @@ -13,7 +13,8 @@ fn main() { let mut stable_path = PathBuf::from(env!("TMPDIR")); stable_path.push("libstable.rmeta"); - let output = rustc().input("main.rs").emit("metadata").extern_("stable", &stable_path).output(); + let output = + rustc().input("main.rs").emit("metadata").extern_("stable", &stable_path).command_output(); let stderr = String::from_utf8_lossy(&output.stderr); let version = include_str!(concat!(env!("S"), "/src/version")); diff --git a/tests/run-make/alloc-no-oom-handling/Makefile b/tests/run-make/alloc-no-oom-handling/Makefile index 87f74c69c7939..7c3ae90b58d67 100644 --- a/tests/run-make/alloc-no-oom-handling/Makefile +++ b/tests/run-make/alloc-no-oom-handling/Makefile @@ -1,3 +1,6 @@ +# This test checks that alloc can still compile correctly when the unstable no_global_oom_handling feature is turned on. +# See https://github.com/rust-lang/rust/pull/84266 + include ../tools.mk all: diff --git a/tests/run-make/alloc-no-rc/Makefile b/tests/run-make/alloc-no-rc/Makefile index 9824b17e6c2a7..fcfe1603b6ce9 100644 --- a/tests/run-make/alloc-no-rc/Makefile +++ b/tests/run-make/alloc-no-rc/Makefile @@ -1,3 +1,6 @@ +# This test checks that alloc can still compile correctly when the unstable no_rc feature is turned on. +# See https://github.com/rust-lang/rust/pull/89891 + include ../tools.mk all: diff --git a/tests/run-make/alloc-no-sync/Makefile b/tests/run-make/alloc-no-sync/Makefile index 04ec4c7d8bc9a..997dbcf66036d 100644 --- a/tests/run-make/alloc-no-sync/Makefile +++ b/tests/run-make/alloc-no-sync/Makefile @@ -1,3 +1,6 @@ +# This test checks that alloc can still compile correctly when the unstable no_sync feature is turned on. +# See https://github.com/rust-lang/rust/pull/89891 + include ../tools.mk all: diff --git a/tests/run-make/allocator-shim-circular-deps/Makefile b/tests/run-make/allocator-shim-circular-deps/Makefile index 4624b84680369..f667e2e2ec293 100644 --- a/tests/run-make/allocator-shim-circular-deps/Makefile +++ b/tests/run-make/allocator-shim-circular-deps/Makefile @@ -1,3 +1,8 @@ +# This test is designed to intentionally introduce a circular dependency scenario to check that a specific compiler bug doesn't make a resurgence. +# The bug in question arose when at least one crate required a global allocator, and that crate was placed after the one defining it in the linker order. +# The generated symbols.o should not result in any linker errors. +# See https://github.com/rust-lang/rust/issues/112715 + # ignore-cross-compile include ../tools.mk diff --git a/tests/run-make/archive-duplicate-names/Makefile b/tests/run-make/archive-duplicate-names/Makefile index 5433a42d25286..207eee392993b 100644 --- a/tests/run-make/archive-duplicate-names/Makefile +++ b/tests/run-make/archive-duplicate-names/Makefile @@ -1,3 +1,7 @@ +# When two object archives with the same filename are present, an iterator is supposed to inspect each object, recognize the duplication and extract each one to a different directory. +# This test checks that this duplicate handling behaviour has not been broken. +# See https://github.com/rust-lang/rust/pull/24439 + # ignore-cross-compile include ../tools.mk diff --git a/tests/run-make/bare-outfile/Makefile b/tests/run-make/bare-outfile/Makefile index 23b619ea0ba32..ad6fe4bd167c4 100644 --- a/tests/run-make/bare-outfile/Makefile +++ b/tests/run-make/bare-outfile/Makefile @@ -1,3 +1,5 @@ +# This test checks that manually setting the output file as a bare file with no file extension still results in successful compilation. + # ignore-cross-compile include ../tools.mk diff --git a/tests/run-make/c-dynamic-dylib/Makefile b/tests/run-make/c-dynamic-dylib/Makefile index b5bfbc7653911..0d40964048678 100644 --- a/tests/run-make/c-dynamic-dylib/Makefile +++ b/tests/run-make/c-dynamic-dylib/Makefile @@ -1,3 +1,6 @@ +# This test checks that dynamic Rust linking with C does not encounter any errors, with dynamic dependencies given preference over static. +# See https://github.com/rust-lang/rust/issues/10434 + # ignore-cross-compile include ../tools.mk diff --git a/tests/run-make/c-dynamic-rlib/Makefile b/tests/run-make/c-dynamic-rlib/Makefile index 0475bd8acae5a..a64e89cc0dc40 100644 --- a/tests/run-make/c-dynamic-rlib/Makefile +++ b/tests/run-make/c-dynamic-rlib/Makefile @@ -1,3 +1,6 @@ +# This test checks that dynamic Rust linking with C does not encounter any errors, with static dependencies given preference over dynamic. (This is the default behaviour.) +# See https://github.com/rust-lang/rust/issues/10434 + # ignore-cross-compile include ../tools.mk diff --git a/tests/run-make/c-link-to-rust-dylib/Makefile b/tests/run-make/c-link-to-rust-dylib/Makefile index 2763cb6ed1d73..201f717ece49c 100644 --- a/tests/run-make/c-link-to-rust-dylib/Makefile +++ b/tests/run-make/c-link-to-rust-dylib/Makefile @@ -1,3 +1,6 @@ +# This test checks that C linking with Rust does not encounter any errors, with dynamic libraries. +# See https://github.com/rust-lang/rust/issues/10434 + # ignore-cross-compile include ../tools.mk diff --git a/tests/run-make/c-link-to-rust-staticlib/Makefile b/tests/run-make/c-link-to-rust-staticlib/Makefile index e14775f5c181c..d36cc421c468a 100644 --- a/tests/run-make/c-link-to-rust-staticlib/Makefile +++ b/tests/run-make/c-link-to-rust-staticlib/Makefile @@ -1,3 +1,6 @@ +# This test checks that C linking with Rust does not encounter any errors, with static libraries. +# See https://github.com/rust-lang/rust/issues/10434 + # ignore-cross-compile include ../tools.mk diff --git a/tests/run-make/c-static-dylib/Makefile b/tests/run-make/c-static-dylib/Makefile index 4e23edb6c57a4..05da1743c83ba 100644 --- a/tests/run-make/c-static-dylib/Makefile +++ b/tests/run-make/c-static-dylib/Makefile @@ -1,3 +1,6 @@ +# This test checks that static Rust linking with C does not encounter any errors, with dynamic dependencies given preference over static. +# See https://github.com/rust-lang/rust/issues/10434 + # ignore-cross-compile include ../tools.mk diff --git a/tests/run-make/c-static-rlib/Makefile b/tests/run-make/c-static-rlib/Makefile index 4e351127cb67c..298e432cdb8ad 100644 --- a/tests/run-make/c-static-rlib/Makefile +++ b/tests/run-make/c-static-rlib/Makefile @@ -1,3 +1,6 @@ +# This test checks that static Rust linking with C does not encounter any errors, with static dependencies given preference over dynamic. (This is the default behaviour.) +# See https://github.com/rust-lang/rust/issues/10434 + # ignore-cross-compile include ../tools.mk diff --git a/tests/run-make/c-unwind-abi-catch-lib-panic/Makefile b/tests/run-make/c-unwind-abi-catch-lib-panic/Makefile index b8e0e9483cd9c..2bb8d42495d3c 100644 --- a/tests/run-make/c-unwind-abi-catch-lib-panic/Makefile +++ b/tests/run-make/c-unwind-abi-catch-lib-panic/Makefile @@ -1,3 +1,6 @@ +# Exercise unwinding a panic. This catches a panic across an FFI boundary and downcasts it into an integer. The Rust code that panics is in a separate crate. +# See https://github.com/rust-lang/rust/commit/baf227ea0c1e07fc54395a51e4b3881d701180cb + # ignore-cross-compile # needs-unwind include ../tools.mk diff --git a/tests/run-make/c-unwind-abi-catch-panic/Makefile b/tests/run-make/c-unwind-abi-catch-panic/Makefile index 1760ddb30616f..0a38d838e32a7 100644 --- a/tests/run-make/c-unwind-abi-catch-panic/Makefile +++ b/tests/run-make/c-unwind-abi-catch-panic/Makefile @@ -1,3 +1,6 @@ +# Exercise unwinding a panic. This catches a panic across an FFI boundary and downcasts it into an integer. The Rust code that panics is in the same directory. +# See https://github.com/rust-lang/rust/commit/baf227ea0c1e07fc54395a51e4b3881d701180cb + # ignore-cross-compile # needs-unwind include ../tools.mk diff --git a/tests/run-make/cat-and-grep-sanity-check/Makefile b/tests/run-make/cat-and-grep-sanity-check/Makefile index 82351e22009b2..8ee69c0a0de19 100644 --- a/tests/run-make/cat-and-grep-sanity-check/Makefile +++ b/tests/run-make/cat-and-grep-sanity-check/Makefile @@ -1,3 +1,7 @@ +# grep in run-make tests was partially replaced with a custom script, CGREP. This tests that CGREP does its job correctly. +# See https://github.com/rust-lang/rust/commit/ab788a2ee175c7560f0ca58bbc183ecfd57d2f7a +# FIXME(Oneirical): Note that this test will likely become useless after the port to rmake.rs tests (see https://github.com/rust-lang/rust/issues/121876) + include ../tools.mk all: diff --git a/tests/run-make/cdylib-dylib-linkage/Makefile b/tests/run-make/cdylib-dylib-linkage/Makefile index 51fbfef2d85f7..db8393d3c05a7 100644 --- a/tests/run-make/cdylib-dylib-linkage/Makefile +++ b/tests/run-make/cdylib-dylib-linkage/Makefile @@ -1,3 +1,6 @@ +# This test checks that cdylibs can link against dylibs as dependencies, after this restriction was disabled. +# See https://github.com/rust-lang/rust/commit/72aaa3a414d17aa0c4f19feafa5bab5f84b60e63 + # ignore-cross-compile include ../tools.mk diff --git a/tests/run-make/cdylib-fewer-symbols/Makefile b/tests/run-make/cdylib-fewer-symbols/Makefile index 4e08f979c36b4..d587cece5bec0 100644 --- a/tests/run-make/cdylib-fewer-symbols/Makefile +++ b/tests/run-make/cdylib-fewer-symbols/Makefile @@ -1,6 +1,8 @@ # ignore-cross-compile + # Test that allocator-related symbols don't show up as exported from a cdylib as # they're internal to Rust and not part of the public ABI. +# See https://github.com/rust-lang/rust/commit/fbf98697021173a30b84d9145df0966a23a2f9d2 include ../tools.mk diff --git a/tests/run-make/cdylib/Makefile b/tests/run-make/cdylib/Makefile index 3c8b526955452..2c6414c32553c 100644 --- a/tests/run-make/cdylib/Makefile +++ b/tests/run-make/cdylib/Makefile @@ -1,3 +1,6 @@ +# When the cdylib crate type was added as a variation of dylib, it needed a test to check its function. +# See https://github.com/rust-lang/rust/pull/33553 + # ignore-cross-compile include ../tools.mk diff --git a/tests/run-make/codegen-options-parsing/Makefile b/tests/run-make/codegen-options-parsing/Makefile index 56bb900b7d8e8..beaf233502bb7 100644 --- a/tests/run-make/codegen-options-parsing/Makefile +++ b/tests/run-make/codegen-options-parsing/Makefile @@ -1,3 +1,5 @@ +# This test intentionally feeds invalid inputs to codegen and checks if the error message outputs contain specific helpful indications. + # ignore-cross-compile include ../tools.mk diff --git a/tests/run-make/comment-section/Makefile b/tests/run-make/comment-section/Makefile index 9f810063cc86d..d0b98176ffed9 100644 --- a/tests/run-make/comment-section/Makefile +++ b/tests/run-make/comment-section/Makefile @@ -1,3 +1,6 @@ +# Both GCC and Clang write by default a `.comment` section with compiler information. Rustc received a similar .comment section, so this tests checks that this section properly appears. +# See https://github.com/rust-lang/rust/commit/74b8d324eb77a8f337b35dc68ac91b0c2c06debc + include ../tools.mk # only-linux diff --git a/tests/run-make/compile-stdin/Makefile b/tests/run-make/compile-stdin/Makefile index 2a495281c247f..b3d7cc777a019 100644 --- a/tests/run-make/compile-stdin/Makefile +++ b/tests/run-make/compile-stdin/Makefile @@ -1,3 +1,6 @@ +# When provided standard input piped directly into rustc, this test checks that the compilation completes successfully and that the output can be executed. +# See https://github.com/rust-lang/rust/pull/28805 + # ignore-cross-compile include ../tools.mk diff --git a/tests/run-make/compiler-lookup-paths-2/Makefile b/tests/run-make/compiler-lookup-paths-2/Makefile index d4ff7d8daabf9..ecc0577384ab6 100644 --- a/tests/run-make/compiler-lookup-paths-2/Makefile +++ b/tests/run-make/compiler-lookup-paths-2/Makefile @@ -1,3 +1,6 @@ +# This test checks that extern crate declarations in Cargo without a corresponding declaration in the manifest of a dependency are NOT allowed. +# See https://github.com/rust-lang/rust/pull/21113 + include ../tools.mk all: diff --git a/tests/run-make/compiler-lookup-paths/Makefile b/tests/run-make/compiler-lookup-paths/Makefile index 310d6772c342c..fc0cbde4c3524 100644 --- a/tests/run-make/compiler-lookup-paths/Makefile +++ b/tests/run-make/compiler-lookup-paths/Makefile @@ -1,3 +1,6 @@ +# rustc supports different types of lookup paths, such as dependency, native or crate. This test checks that these lookup paths are functional and result in functional compilation. +# See https://github.com/rust-lang/rust/pull/19941 + include ../tools.mk # ignore-wasm32 (need a C compiler) diff --git a/tests/run-make/doctests-runtool/Makefile b/tests/run-make/doctests-runtool/Makefile deleted file mode 100644 index 7d5df1e307fb8..0000000000000 --- a/tests/run-make/doctests-runtool/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# Tests behavior of rustdoc --runtool - -MY_SRC_DIR := ${CURDIR} - -all: with_test_run_directory - -# Behavior with --runtool with relative paths and --test-run-directory. -with_test_run_directory: - mkdir -p $(TMPDIR)/rundir - mkdir -p $(TMPDIR)/runtool - $(RUSTC) --crate-type rlib t.rs - $(RUSTC) runtool.rs -o $(TMPDIR)/runtool/runtool - ( cd $(TMPDIR); \ - $(RUSTDOC) -Zunstable-options --test --test-run-directory rundir \ - --runtool runtool/runtool --extern t=libt.rlib $(MY_SRC_DIR)/t.rs \ - ) - rm -rf $(TMPDIR)/rundir $(TMPDIR)/runtool diff --git a/tests/run-make/doctests-runtool/rmake.rs b/tests/run-make/doctests-runtool/rmake.rs new file mode 100644 index 0000000000000..6f89bf23b47c4 --- /dev/null +++ b/tests/run-make/doctests-runtool/rmake.rs @@ -0,0 +1,39 @@ +// Tests behavior of rustdoc `--runtool`. + +use run_make_support::{rustc, rustdoc, tmp_dir}; +use std::env::current_dir; +use std::fs::{create_dir, remove_dir_all}; +use std::path::PathBuf; + +fn mkdir(name: &str) -> PathBuf { + let dir = tmp_dir().join(name); + create_dir(&dir).expect("failed to create doctests folder"); + dir +} + +// Behavior with --runtool with relative paths and --test-run-directory. +fn main() { + let run_dir_name = "rundir"; + let run_dir = mkdir(run_dir_name); + let run_tool = mkdir("runtool"); + let run_tool_binary = run_tool.join("runtool"); + + rustc().input("t.rs").crate_type("rlib").run(); + rustc().input("runtool.rs").output(&run_tool_binary).run(); + + rustdoc() + .input(current_dir().unwrap().join("t.rs")) + .arg("-Zunstable-options") + .arg("--test") + .arg("--test-run-directory") + .arg(run_dir_name) + .arg("--runtool") + .arg(&run_tool_binary) + .arg("--extern") + .arg("t=libt.rlib") + .current_dir(tmp_dir()) + .run(); + + remove_dir_all(run_dir); + remove_dir_all(run_tool); +} diff --git a/tests/run-make/exit-code/rmake.rs b/tests/run-make/exit-code/rmake.rs index b1143153d0af0..76d7777581b5e 100644 --- a/tests/run-make/exit-code/rmake.rs +++ b/tests/run-make/exit-code/rmake.rs @@ -15,7 +15,7 @@ fn main() { .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("success.rs").output(tmp_dir().join("exit-code")).run(); rustdoc().arg("--invalid-arg-foo").run_fail_assert_exit_code(1); diff --git a/tests/run-make/libtest-padding/Makefile b/tests/run-make/libtest-padding/Makefile index 42bc1192925d8..c8e2fc01f677d 100644 --- a/tests/run-make/libtest-padding/Makefile +++ b/tests/run-make/libtest-padding/Makefile @@ -2,7 +2,7 @@ # needs-unwind because #[bench] and -Cpanic=abort requires -Zpanic-abort-tests include ../tools.mk -NORMALIZE=sed 's%[0-9,]\{1,\} ns/iter (+/- [0-9,]\{1,\})%?? ns/iter (+/- ??)%' | sed 's%finished in [0-9\.]\{1,\}%finished in ??%' +NORMALIZE=sed 's%[0-9,\.]\{1,\} ns/iter (+/- [0-9,\.]\{1,\})%?? ns/iter (+/- ??)%' | sed 's%finished in [0-9\.]\{1,\}%finished in ??%' all: $(RUSTC) --test tests.rs diff --git a/tests/run-make/repr128-dwarf/rmake.rs b/tests/run-make/repr128-dwarf/rmake.rs index d734b2add79a2..fd5dd81044419 100644 --- a/tests/run-make/repr128-dwarf/rmake.rs +++ b/tests/run-make/repr128-dwarf/rmake.rs @@ -10,7 +10,7 @@ use std::rc::Rc; fn main() { let output = tmp_dir().join("repr128"); - rustc().input("main.rs").arg("-o").arg(&output).arg("-Cdebuginfo=2").run(); + rustc().input("main.rs").output(&output).arg("-Cdebuginfo=2").run(); // Mach-O uses packed debug info let dsym_location = output .with_extension("dSYM") diff --git a/tests/run-make/rustdoc-determinism/rmake.rs b/tests/run-make/rustdoc-determinism/rmake.rs index 38ae75199fd83..09097d4507daf 100644 --- a/tests/run-make/rustdoc-determinism/rmake.rs +++ b/tests/run-make/rustdoc-determinism/rmake.rs @@ -1,18 +1,19 @@ -use run_make_support::{diff, rustc, rustdoc, tmp_dir}; +// Assert that the search index is generated deterministically, regardless of the +// order that crates are documented in. + +use run_make_support::{diff, rustdoc, tmp_dir}; -/// Assert that the search index is generated deterministically, regardless of the -/// order that crates are documented in. fn main() { - let dir_first = tmp_dir().join("first"); - rustdoc().out_dir(&dir_first).input("foo.rs").run(); - rustdoc().out_dir(&dir_first).input("bar.rs").run(); + let foo_first = tmp_dir().join("foo_first"); + rustdoc().input("foo.rs").output(&foo_first).run(); + rustdoc().input("bar.rs").output(&foo_first).run(); - let dir_second = tmp_dir().join("second"); - rustdoc().out_dir(&dir_second).input("bar.rs").run(); - rustdoc().out_dir(&dir_second).input("foo.rs").run(); + let bar_first = tmp_dir().join("bar_first"); + rustdoc().input("bar.rs").output(&bar_first).run(); + rustdoc().input("foo.rs").output(&bar_first).run(); diff() - .expected_file(dir_first.join("search-index.js")) - .actual_file(dir_second.join("search-index.js")) + .expected_file(foo_first.join("search-index.js")) + .actual_file(bar_first.join("search-index.js")) .run(); } diff --git a/tests/run-make/rustdoc-error-lines/Makefile b/tests/run-make/rustdoc-error-lines/Makefile deleted file mode 100644 index 2dc30f56b833f..0000000000000 --- a/tests/run-make/rustdoc-error-lines/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -include ../tools.mk - -# Test that hir-tree output doesn't crash and includes -# the string constant we would expect to see. - -all: - $(RUSTDOC) --test input.rs > $(TMPDIR)/output || true - $(CGREP) 'input.rs - foo (line 5)' < $(TMPDIR)/output - $(CGREP) 'input.rs:7:15' < $(TMPDIR)/output - $(CGREP) 'input.rs - bar (line 15)' < $(TMPDIR)/output - $(CGREP) 'input.rs:17:15' < $(TMPDIR)/output - $(CGREP) 'input.rs - bar (line 24)' < $(TMPDIR)/output - $(CGREP) 'input.rs:26:15' < $(TMPDIR)/output diff --git a/tests/run-make/rustdoc-error-lines/rmake.rs b/tests/run-make/rustdoc-error-lines/rmake.rs new file mode 100644 index 0000000000000..31536c78dd460 --- /dev/null +++ b/tests/run-make/rustdoc-error-lines/rmake.rs @@ -0,0 +1,22 @@ +// Assert that the search index is generated deterministically, regardless of the +// order that crates are documented in. + +use run_make_support::rustdoc; + +fn main() { + let output = + String::from_utf8(rustdoc().input("input.rs").arg("--test").command_output().stdout) + .unwrap(); + + let should_contain = &[ + "input.rs - foo (line 5)", + "input.rs:7:15", + "input.rs - bar (line 15)", + "input.rs:17:15", + "input.rs - bar (line 24)", + "input.rs:26:15", + ]; + for text in should_contain { + assert!(output.contains(text), "output doesn't contains {:?}", text); + } +} diff --git a/tests/run-make/rustdoc-map-file/Makefile b/tests/run-make/rustdoc-map-file/Makefile deleted file mode 100644 index 5cbf7747af638..0000000000000 --- a/tests/run-make/rustdoc-map-file/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -include ../tools.mk - -all: - $(RUSTDOC) -Z unstable-options --generate-redirect-map foo.rs -o "$(TMPDIR)/out" - "$(PYTHON)" validate_json.py "$(TMPDIR)/out" diff --git a/tests/run-make/rustdoc-map-file/rmake.rs b/tests/run-make/rustdoc-map-file/rmake.rs new file mode 100644 index 0000000000000..aaa7fea0b6b78 --- /dev/null +++ b/tests/run-make/rustdoc-map-file/rmake.rs @@ -0,0 +1,15 @@ +use run_make_support::{rustdoc, tmp_dir}; +use std::process::Command; + +fn main() { + let out_dir = tmp_dir().join("out"); + rustdoc() + .input("foo.rs") + .arg("-Zunstable-options") + .arg("--generate-redirect-map") + .output(&out_dir) + .run(); + // FIXME (GuillaumeGomez): Port the python script to Rust as well. + let python = std::env::var("PYTHON").unwrap_or("python".into()); + assert!(Command::new(python).arg("validate_json.py").arg(&out_dir).status().unwrap().success()); +} diff --git a/tests/run-make/rustdoc-output-path/Makefile b/tests/run-make/rustdoc-output-path/Makefile deleted file mode 100644 index 8f5cda9e56e9f..0000000000000 --- a/tests/run-make/rustdoc-output-path/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -include ../tools.mk - -all: - $(RUSTDOC) -o "$(TMPDIR)/foo/bar/doc" foo.rs diff --git a/tests/run-make/rustdoc-output-path/rmake.rs b/tests/run-make/rustdoc-output-path/rmake.rs new file mode 100644 index 0000000000000..74fb0a56ac630 --- /dev/null +++ b/tests/run-make/rustdoc-output-path/rmake.rs @@ -0,0 +1,9 @@ +// Checks that if the output folder doesn't exist, rustdoc will create it. + +use run_make_support::{rustdoc, tmp_dir}; + +fn main() { + let out_dir = tmp_dir().join("foo/bar/doc"); + rustdoc().input("foo.rs").output(&out_dir).run(); + assert!(out_dir.exists()); +} diff --git a/tests/run-make/rustdoc-scrape-examples-ordering/Makefile b/tests/run-make/rustdoc-scrape-examples-ordering/Makefile deleted file mode 100644 index bf45b8148c03a..0000000000000 --- a/tests/run-make/rustdoc-scrape-examples-ordering/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -deps := ex1 ex2 - -include ../rustdoc-scrape-examples-multiple/scrape.mk - -all: scrape diff --git a/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs b/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs new file mode 100644 index 0000000000000..edcf3406d47f8 --- /dev/null +++ b/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs @@ -0,0 +1,55 @@ +use run_make_support::{python_command, rustc, rustdoc, source_path, tmp_dir}; +use std::fs::read_dir; +use std::path::Path; + +fn main() { + let lib_dir = tmp_dir(); + let out_dir = tmp_dir().join("rustdoc"); + let crate_name = "foobar"; + let deps = read_dir("examples") + .unwrap() + .filter_map(|entry| entry.ok().map(|e| e.path())) + .filter(|path| path.is_file() && path.extension().is_some_and(|ext| ext == "rs")) + .collect::>(); + + rustc().input("src/lib.rs").crate_name(crate_name).crate_type("lib").emit("metadata").run(); + + let mut out_deps = Vec::with_capacity(deps.len()); + for dep in deps { + let dep_stem = dep.file_stem().unwrap(); + let out_example = out_dir.join(format!("{}.calls", dep_stem.to_str().unwrap())); + rustdoc() + .input(&dep) + .crate_name(&dep_stem) + .crate_type("bin") + .output(&out_dir) + .extern_(crate_name, lib_dir.join(format!("lib{crate_name}.rmeta"))) + .arg("-Zunstable-options") + .arg("--scrape-examples-output-path") + .arg(&out_example) + .arg("--scrape-examples-target-crate") + .arg(crate_name) + .run(); + out_deps.push(out_example); + } + + let mut rustdoc = rustdoc(); + rustdoc + .input("src/lib.rs") + .output(&out_dir) + .crate_name(crate_name) + .crate_type("lib") + .arg("-Zunstable-options"); + for dep in out_deps { + rustdoc.arg("--with-examples").arg(dep); + } + rustdoc.run(); + + python_command() + .arg(source_path().join("/src/etc/htmldocck.py")) + .arg(out_dir) + .arg("src/lib.rs") + .status() + .unwrap() + .success(); +} diff --git a/tests/run-make/rustdoc-shared-flags/Makefile b/tests/run-make/rustdoc-shared-flags/Makefile deleted file mode 100644 index a2a7d7b3634a9..0000000000000 --- a/tests/run-make/rustdoc-shared-flags/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -include ../tools.mk - -all: z_help c_help list_passes - -c_help: - $(RUSTC) -C help > $(TMPDIR)/rustc.c_help.txt - $(RUSTDOC) -C help > $(TMPDIR)/rustdoc.c_help.txt - $(DIFF) $(TMPDIR)/rustc.c_help.txt $(TMPDIR)/rustdoc.c_help.txt - -z_help: - $(RUSTC) -Z help > $(TMPDIR)/rustc.z_help.txt - $(RUSTDOC) -Z help > $(TMPDIR)/rustdoc.z_help.txt - $(DIFF) $(TMPDIR)/rustc.z_help.txt $(TMPDIR)/rustdoc.z_help.txt - -list_passes: - $(RUSTC) -C passes=list > $(TMPDIR)/rustc.passes.txt - $(RUSTDOC) -C passes=list > $(TMPDIR)/rustdoc.passes.txt - $(DIFF) $(TMPDIR)/rustc.passes.txt $(TMPDIR)/rustdoc.passes.txt diff --git a/tests/run-make/rustdoc-shared-flags/rmake.rs b/tests/run-make/rustdoc-shared-flags/rmake.rs new file mode 100644 index 0000000000000..2db613f781764 --- /dev/null +++ b/tests/run-make/rustdoc-shared-flags/rmake.rs @@ -0,0 +1,14 @@ +use run_make_support::{rustc, rustdoc, Diff}; + +fn compare_outputs(args: &[&str]) { + let rustc_output = String::from_utf8(rustc().args(args).command_output().stdout).unwrap(); + let rustdoc_output = String::from_utf8(rustdoc().args(args).command_output().stdout).unwrap(); + + Diff::new().expected_text("rustc", rustc_output).actual_text("rustdoc", rustdoc_output).run(); +} + +fn main() { + compare_outputs(&["-C", "help"]); + compare_outputs(&["-Z", "help"]); + compare_outputs(&["-C", "passes=list"]); +} diff --git a/tests/rustdoc-gui/javascript-disabled.goml b/tests/rustdoc-gui/javascript-disabled.goml index a7579ef7ec14d..c6a7ad94b3fd7 100644 --- a/tests/rustdoc-gui/javascript-disabled.goml +++ b/tests/rustdoc-gui/javascript-disabled.goml @@ -4,7 +4,7 @@ javascript: false go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html" show-text: true -assert-css: (".sub", {"display": "none"}) +assert-false: ".sub" // Even though JS is disabled, we should still have themes applied. Links are never black-colored // if styles are applied so we check that they are not. diff --git a/tests/rustdoc-gui/sidebar-source-code-display.goml b/tests/rustdoc-gui/sidebar-source-code-display.goml index 3bfbe820b8dfe..7ce3be8a5b355 100644 --- a/tests/rustdoc-gui/sidebar-source-code-display.goml +++ b/tests/rustdoc-gui/sidebar-source-code-display.goml @@ -4,7 +4,7 @@ javascript: false go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" // Since the javascript is disabled, there shouldn't be a toggle. wait-for-css: (".sidebar", {"display": "none"}) -assert-css: ("#sidebar-button", {"display": "none"}) +assert-false: "#sidebar-button" // Let's retry with javascript enabled. javascript: true diff --git a/tests/rustdoc-ui/issues/issue-91713.stdout b/tests/rustdoc-ui/issues/issue-91713.stdout index bbea7e5c212ef..cc3c8385d9a8e 100644 --- a/tests/rustdoc-ui/issues/issue-91713.stdout +++ b/tests/rustdoc-ui/issues/issue-91713.stdout @@ -1,6 +1,7 @@ Available passes for running rustdoc: check-custom-code-classes - check for custom code classes without the feature-gate enabled check_doc_test_visibility - run various visibility-related lints on doctests +strip-aliased-non-local - strips all non-local private aliased items from the output strip-hidden - strips all `#[doc(hidden)]` items from the output strip-private - strips all private items from a crate which cannot be seen externally, implies strip-priv-imports strip-priv-imports - strips all private import statements (`use`, `extern crate`) from a crate @@ -14,6 +15,7 @@ Default passes for rustdoc: check-custom-code-classes collect-trait-impls check_doc_test_visibility +strip-aliased-non-local strip-hidden (when not --document-hidden-items) strip-private (when not --document-private-items) strip-priv-imports (when --document-private-items) diff --git a/tests/rustdoc/inline_cross/issue-76736-2.rs b/tests/rustdoc/inline_cross/issue-76736-2.rs index 83529dd1887c4..d4e6a697fc81d 100644 --- a/tests/rustdoc/inline_cross/issue-76736-2.rs +++ b/tests/rustdoc/inline_cross/issue-76736-2.rs @@ -1,6 +1,8 @@ //@ aux-build:issue-76736-1.rs //@ aux-build:issue-76736-2.rs +// https://github.com/rust-lang/rust/issues/124635 + #![crate_name = "foo"] #![feature(rustc_private)] @@ -8,9 +10,9 @@ extern crate issue_76736_1; extern crate issue_76736_2; // @has foo/struct.Foo.html -// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult' +// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult' pub struct Foo; // @has foo/struct.Bar.html -// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult' +// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult' pub use issue_76736_2::Bar; diff --git a/tests/rustdoc/inline_cross/issue-76736-4.rs b/tests/rustdoc/inline_cross/issue-76736-4.rs new file mode 100644 index 0000000000000..297657ef9de58 --- /dev/null +++ b/tests/rustdoc/inline_cross/issue-76736-4.rs @@ -0,0 +1,19 @@ +//@ aux-build:issue-76736-1.rs +//@ aux-build:issue-76736-2.rs + +// https://github.com/rust-lang/rust/issues/124635 + +#![crate_name = "foo"] +#![feature(rustc_private, staged_api)] +#![unstable(feature = "rustc_private", issue = "none")] + +extern crate issue_76736_1; +extern crate issue_76736_2; + +// @has foo/struct.Foo.html +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult' +pub struct Foo; + +// @has foo/struct.Bar.html +// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult' +pub use issue_76736_2::Bar; diff --git a/tests/rustdoc/private-non-local-fields-2.rs b/tests/rustdoc/private-non-local-fields-2.rs new file mode 100644 index 0000000000000..615b957f697e8 --- /dev/null +++ b/tests/rustdoc/private-non-local-fields-2.rs @@ -0,0 +1,11 @@ +//! This test makes sure that with never show the inner fields in the +//! aliased type view of type alias. + +//@ compile-flags: -Z unstable-options --document-private-items + +#![crate_name = "foo"] + +use std::collections::BTreeMap; + +// @has 'foo/type.FooBar.html' '//*[@class="rust item-decl"]/code' 'struct FooBar { /* private fields */ }' +pub type FooBar = BTreeMap; diff --git a/tests/rustdoc/private-non-local-fields.rs b/tests/rustdoc/private-non-local-fields.rs new file mode 100644 index 0000000000000..7922ce074dd1b --- /dev/null +++ b/tests/rustdoc/private-non-local-fields.rs @@ -0,0 +1,9 @@ +//! This test makes sure that with never show the inner fields in the +//! aliased type view of type alias. + +#![crate_name = "foo"] + +use std::collections::BTreeMap; + +// @has 'foo/type.FooBar.html' '//*[@class="rust item-decl"]/code' 'struct FooBar { /* private fields */ }' +pub type FooBar = BTreeMap; diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs index 475a69f4ad098..2b1fec9438717 100644 --- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs @@ -180,7 +180,10 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P)) { 18 => { let pat = P(Pat { id: DUMMY_NODE_ID, kind: PatKind::Wild, span: DUMMY_SP, tokens: None }); - iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(pat.clone(), e, DUMMY_SP, None))) + iter_exprs( + depth - 1, + &mut |e| g(ExprKind::Let(pat.clone(), e, DUMMY_SP, Recovered::No)) + ) } _ => panic!("bad counter value in iter_exprs"), } diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs index 74801e007c4dd..359dd4146baf5 100644 --- a/tests/ui-fulldeps/stable-mir/check_abi.rs +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -99,7 +99,7 @@ fn check_result(abi: &ArgAbi) { assert_matches!(layout.variants, VariantsShape::Multiple { .. }) } -/// Check the niche information about: `NonZeroU8` +/// Checks the niche information about `NonZero`. fn check_niche(abi: &ArgAbi) { assert!(abi.ty.kind().is_struct()); assert_matches!(abi.mode, PassMode::Direct { .. }); @@ -150,12 +150,12 @@ fn generate_input(path: &str) -> std::io::Result<()> { #![feature(c_variadic)] #![allow(unused_variables)] - use std::num::NonZeroU8; + use std::num::NonZero; pub fn fn_abi( ignore: [u8; 0], primitive: char, - niche: NonZeroU8, + niche: NonZero, ) -> Result {{ // We only care about the signature. todo!() diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr index 00fc7d1ece1d9..7365839da89dc 100644 --- a/tests/ui/abi/debug.stderr +++ b/tests/ui/abi/debug.stderr @@ -576,7 +576,9 @@ error: ABIs are not compatible }, abi: Scalar( Initialized { - value: F32, + value: Float( + F32, + ), valid_range: $FULL, }, ), diff --git a/tests/ui/abi/extern/auxiliary/extern-crosscrate-source.rs b/tests/ui/abi/extern/auxiliary/extern-crosscrate-source.rs index 9c61518b94142..6b21877109664 100644 --- a/tests/ui/abi/extern/auxiliary/extern-crosscrate-source.rs +++ b/tests/ui/abi/extern/auxiliary/extern-crosscrate-source.rs @@ -1,28 +1,21 @@ #![crate_name = "externcallback"] #![crate_type = "lib"] -#![feature(rustc_private)] -extern crate libc; - -pub mod rustrt { - extern crate libc; - - #[link(name = "rust_test_helpers", kind = "static")] - extern "C" { - pub fn rust_dbg_call( - cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t, - data: libc::uintptr_t, - ) -> libc::uintptr_t; - } +#[link(name = "rust_test_helpers", kind = "static")] +extern "C" { + pub fn rust_dbg_call( + cb: extern "C" fn(u64) -> u64, + data: u64, + ) -> u64; } -pub fn fact(n: libc::uintptr_t) -> libc::uintptr_t { +pub fn fact(n: u64) -> u64 { unsafe { println!("n = {}", n); - rustrt::rust_dbg_call(cb, n) + rust_dbg_call(cb, n) } } -pub extern "C" fn cb(data: libc::uintptr_t) -> libc::uintptr_t { +pub extern "C" fn cb(data: u64) -> u64 { if data == 1 { data } else { fact(data - 1) * data } } diff --git a/tests/ui/abi/extern/extern-call-deep.rs b/tests/ui/abi/extern/extern-call-deep.rs index 062e70b1b6ee5..40457ae57207d 100644 --- a/tests/ui/abi/extern/extern-call-deep.rs +++ b/tests/ui/abi/extern/extern-call-deep.rs @@ -1,35 +1,27 @@ //@ run-pass //@ ignore-emscripten blows the JS stack -#![feature(rustc_private)] - -extern crate libc; - -mod rustrt { - extern crate libc; - - #[link(name = "rust_test_helpers", kind = "static")] - extern "C" { - pub fn rust_dbg_call( - cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t, - data: libc::uintptr_t, - ) -> libc::uintptr_t; - } +#[link(name = "rust_test_helpers", kind = "static")] +extern "C" { + pub fn rust_dbg_call( + cb: extern "C" fn(u64) -> u64, + data: u64, + ) -> u64; } -extern "C" fn cb(data: libc::uintptr_t) -> libc::uintptr_t { +extern "C" fn cb(data: u64) -> u64 { if data == 1 { data } else { count(data - 1) + 1 } } -fn count(n: libc::uintptr_t) -> libc::uintptr_t { +fn count(n: u64) -> u64 { unsafe { println!("n = {}", n); - rustrt::rust_dbg_call(cb, n) + rust_dbg_call(cb, n) } } pub fn main() { let result = count(1000); - println!("result = {}", result); + println!("result = {:?}", result); assert_eq!(result, 1000); } diff --git a/tests/ui/abi/extern/extern-call-deep2.rs b/tests/ui/abi/extern/extern-call-deep2.rs index c021bc223482d..91ca28d80c80f 100644 --- a/tests/ui/abi/extern/extern-call-deep2.rs +++ b/tests/ui/abi/extern/extern-call-deep2.rs @@ -1,31 +1,24 @@ //@ run-pass -#![allow(unused_must_use)] //@ needs-threads -#![feature(rustc_private)] -extern crate libc; use std::thread; -mod rustrt { - extern crate libc; - - #[link(name = "rust_test_helpers", kind = "static")] - extern "C" { - pub fn rust_dbg_call( - cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t, - data: libc::uintptr_t, - ) -> libc::uintptr_t; - } +#[link(name = "rust_test_helpers", kind = "static")] +extern "C" { + pub fn rust_dbg_call( + cb: extern "C" fn(u64) -> u64, + data: u64, + ) -> u64; } -extern "C" fn cb(data: libc::uintptr_t) -> libc::uintptr_t { - if data == 1 { data } else { count(data - 1) + 1 } +extern "C" fn cb(data: u64) -> u64 { + if data == 1 { data } else { count(data - 1 ) + 1 } } -fn count(n: libc::uintptr_t) -> libc::uintptr_t { +fn count(n: u64) -> u64 { unsafe { println!("n = {}", n); - rustrt::rust_dbg_call(cb, n) + rust_dbg_call(cb, n) } } @@ -37,5 +30,5 @@ pub fn main() { println!("result = {}", result); assert_eq!(result, 1000); }) - .join(); + .join().unwrap(); } diff --git a/tests/ui/abi/extern/extern-call-indirect.rs b/tests/ui/abi/extern/extern-call-indirect.rs index 18fb07d8c8bbd..ef1e8ae5e760d 100644 --- a/tests/ui/abi/extern/extern-call-indirect.rs +++ b/tests/ui/abi/extern/extern-call-indirect.rs @@ -1,29 +1,21 @@ //@ run-pass -#![feature(rustc_private)] - -extern crate libc; - -mod rustrt { - extern crate libc; - - #[link(name = "rust_test_helpers", kind = "static")] - extern "C" { - pub fn rust_dbg_call( - cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t, - data: libc::uintptr_t, - ) -> libc::uintptr_t; - } +#[link(name = "rust_test_helpers", kind = "static")] +extern "C" { + pub fn rust_dbg_call( + cb: extern "C" fn(u64) -> u64, + data: u64, + ) -> u64; } -extern "C" fn cb(data: libc::uintptr_t) -> libc::uintptr_t { +extern "C" fn cb(data: u64) -> u64 { if data == 1 { data } else { fact(data - 1) * data } } -fn fact(n: libc::uintptr_t) -> libc::uintptr_t { +fn fact(n: u64) -> u64 { unsafe { println!("n = {}", n); - rustrt::rust_dbg_call(cb, n) + rust_dbg_call(cb, n) } } diff --git a/tests/ui/abi/extern/extern-call-scrub.rs b/tests/ui/abi/extern/extern-call-scrub.rs index 7edf8975ad816..7df3a8f04ef1f 100644 --- a/tests/ui/abi/extern/extern-call-scrub.rs +++ b/tests/ui/abi/extern/extern-call-scrub.rs @@ -1,35 +1,27 @@ //@ run-pass -#![allow(unused_must_use)] +//@ needs-threads // This time we're testing repeatedly going up and down both stacks to // make sure the stack pointers are maintained properly in both // directions -//@ needs-threads -#![feature(rustc_private)] - -extern crate libc; use std::thread; -mod rustrt { - extern crate libc; - - #[link(name = "rust_test_helpers", kind = "static")] - extern "C" { - pub fn rust_dbg_call( - cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t, - data: libc::uintptr_t, - ) -> libc::uintptr_t; - } +#[link(name = "rust_test_helpers", kind = "static")] +extern "C" { + pub fn rust_dbg_call( + cb: extern "C" fn(u64) -> u64, + data: u64, + ) -> u64; } -extern "C" fn cb(data: libc::uintptr_t) -> libc::uintptr_t { +extern "C" fn cb(data: u64) -> u64 { if data == 1 { data } else { count(data - 1) + count(data - 1) } } -fn count(n: libc::uintptr_t) -> libc::uintptr_t { +fn count(n: u64) -> u64 { unsafe { println!("n = {}", n); - rustrt::rust_dbg_call(cb, n) + rust_dbg_call(cb, n) } } @@ -41,5 +33,5 @@ pub fn main() { println!("result = {}", result); assert_eq!(result, 2048); }) - .join(); + .join().unwrap(); } diff --git a/tests/ui/abi/extern/extern-crosscrate.rs b/tests/ui/abi/extern/extern-crosscrate.rs index c283cbe321637..b467d9929844a 100644 --- a/tests/ui/abi/extern/extern-crosscrate.rs +++ b/tests/ui/abi/extern/extern-crosscrate.rs @@ -1,15 +1,12 @@ //@ run-pass //@ aux-build:extern-crosscrate-source.rs -#![feature(rustc_private)] - extern crate externcallback; -extern crate libc; -fn fact(n: libc::uintptr_t) -> libc::uintptr_t { +fn fact(n: u64) -> u64 { unsafe { - println!("n = {}", n); - externcallback::rustrt::rust_dbg_call(externcallback::cb, n) + println!("n = {:?}", n); + externcallback::rust_dbg_call(externcallback::cb, n) } } diff --git a/tests/ui/abi/foreign/foreign-call-no-runtime.rs b/tests/ui/abi/foreign/foreign-call-no-runtime.rs deleted file mode 100644 index fccd62b6100f3..0000000000000 --- a/tests/ui/abi/foreign/foreign-call-no-runtime.rs +++ /dev/null @@ -1,60 +0,0 @@ -//@ run-pass -//@ needs-threads - -#![feature(rustc_private)] - -extern crate libc; - -use std::mem; -use std::thread; - -#[link(name = "rust_test_helpers", kind = "static")] -extern "C" { - fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t), data: libc::uintptr_t) -> libc::uintptr_t; -} - -pub fn main() { - unsafe { - thread::spawn(move || { - let i: isize = 100; - rust_dbg_call(callback_isize, mem::transmute(&i)); - }) - .join() - .unwrap(); - - thread::spawn(move || { - let i: i32 = 100; - rust_dbg_call(callback_i32, mem::transmute(&i)); - }) - .join() - .unwrap(); - - thread::spawn(move || { - let i: i64 = 100; - rust_dbg_call(callback_i64, mem::transmute(&i)); - }) - .join() - .unwrap(); - } -} - -extern "C" fn callback_isize(data: libc::uintptr_t) { - unsafe { - let data = data as *const isize; - assert_eq!(*data, 100); - } -} - -extern "C" fn callback_i64(data: libc::uintptr_t) { - unsafe { - let data = data as *const i64; - assert_eq!(*data, 100); - } -} - -extern "C" fn callback_i32(data: libc::uintptr_t) { - unsafe { - let data = data as *const i32; - assert_eq!(*data, 100); - } -} diff --git a/tests/ui/associated-types/bound-lifetime-constrained.ok.stderr b/tests/ui/associated-types/bound-lifetime-constrained.ok.stderr new file mode 100644 index 0000000000000..9082044fe068b --- /dev/null +++ b/tests/ui/associated-types/bound-lifetime-constrained.ok.stderr @@ -0,0 +1,8 @@ +error: fatal error triggered by #[rustc_error] + --> $DIR/bound-lifetime-constrained.rs:48:1 + | +LL | fn main() { } + | ^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/associated-types/bound-lifetime-constrained.rs b/tests/ui/associated-types/bound-lifetime-constrained.rs index 880d350bdf602..1dc3b2f5c2b77 100644 --- a/tests/ui/associated-types/bound-lifetime-constrained.rs +++ b/tests/ui/associated-types/bound-lifetime-constrained.rs @@ -1,4 +1,4 @@ -//@ revisions: func object clause +//@ revisions: func object clause ok #![allow(dead_code)] #![feature(rustc_attrs)] diff --git a/tests/ui/async-await/async-block-control-flow-static-semantics.rs b/tests/ui/async-await/async-block-control-flow-static-semantics.rs index 0ef7cb7574a90..6e04c535cf11f 100644 --- a/tests/ui/async-await/async-block-control-flow-static-semantics.rs +++ b/tests/ui/async-await/async-block-control-flow-static-semantics.rs @@ -29,14 +29,14 @@ async fn return_targets_async_block_not_async_fn() -> u8 { fn no_break_in_async_block() { async { - break 0u8; //~ ERROR `break` inside of an `async` block + break 0u8; //~ ERROR `break` inside `async` block }; } fn no_break_in_async_block_even_with_outer_loop() { loop { async { - break 0u8; //~ ERROR `break` inside of an `async` block + break 0u8; //~ ERROR `break` inside `async` block }; } } diff --git a/tests/ui/async-await/async-block-control-flow-static-semantics.stderr b/tests/ui/async-await/async-block-control-flow-static-semantics.stderr index c89671cc4811b..ce0d003f0142e 100644 --- a/tests/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/tests/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -1,18 +1,18 @@ -error[E0267]: `break` inside of an `async` block +error[E0267]: `break` inside `async` block --> $DIR/async-block-control-flow-static-semantics.rs:32:9 | LL | / async { LL | | break 0u8; - | | ^^^^^^^^^ cannot `break` inside of an `async` block + | | ^^^^^^^^^ cannot `break` inside `async` block LL | | }; | |_____- enclosing `async` block -error[E0267]: `break` inside of an `async` block +error[E0267]: `break` inside `async` block --> $DIR/async-block-control-flow-static-semantics.rs:39:13 | LL | / async { LL | | break 0u8; - | | ^^^^^^^^^ cannot `break` inside of an `async` block + | | ^^^^^^^^^ cannot `break` inside `async` block LL | | }; | |_________- enclosing `async` block diff --git a/tests/ui/async-await/async-closures/ambiguous-arg.rs b/tests/ui/async-await/async-closures/ambiguous-arg.rs new file mode 100644 index 0000000000000..d76a1cf953e46 --- /dev/null +++ b/tests/ui/async-await/async-closures/ambiguous-arg.rs @@ -0,0 +1,15 @@ +//@ edition:2021 + +// Regression test for #123901. We previously ICE'd as we silently +// swallowed an in the `ExprUseVisitor`. + +#![feature(async_closure)] + +pub fn test(test: &u64, temp: &u64) { + async |check, a, b| { + //~^ ERROR type annotations needed + temp.abs_diff(12); + }; +} + +fn main() {} diff --git a/tests/ui/async-await/async-closures/ambiguous-arg.stderr b/tests/ui/async-await/async-closures/ambiguous-arg.stderr new file mode 100644 index 0000000000000..01f72e94eccf7 --- /dev/null +++ b/tests/ui/async-await/async-closures/ambiguous-arg.stderr @@ -0,0 +1,13 @@ +error[E0282]: type annotations needed + --> $DIR/ambiguous-arg.rs:9:25 + | +LL | async |check, a, b| { + | _________________________^ +LL | | +LL | | temp.abs_diff(12); +LL | | }; + | |_____^ cannot infer type + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/attributes/nonterminal-expansion.rs b/tests/ui/attributes/nonterminal-expansion.rs index 6db7aea07458e..1b2e92a31703c 100644 --- a/tests/ui/attributes/nonterminal-expansion.rs +++ b/tests/ui/attributes/nonterminal-expansion.rs @@ -5,7 +5,7 @@ macro_rules! pass_nonterminal { ($n:expr) => { #[repr(align($n))] - //~^ ERROR expected unsuffixed literal or identifier, found `n!()` + //~^ ERROR expected unsuffixed literal, found `n!()` struct S; }; } diff --git a/tests/ui/attributes/nonterminal-expansion.stderr b/tests/ui/attributes/nonterminal-expansion.stderr index 78541495b3284..b640575d17dc7 100644 --- a/tests/ui/attributes/nonterminal-expansion.stderr +++ b/tests/ui/attributes/nonterminal-expansion.stderr @@ -1,4 +1,4 @@ -error: expected unsuffixed literal or identifier, found `n!()` +error: expected unsuffixed literal, found `n!()` --> $DIR/nonterminal-expansion.rs:7:22 | LL | #[repr(align($n))] diff --git a/tests/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr b/tests/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr index aacf178932e6e..6cd64c58cab2f 100644 --- a/tests/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr +++ b/tests/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-activation-sharing-interference.rs:28:15 + --> $DIR/two-phase-activation-sharing-interference.rs:29:15 | LL | let y = &mut x; | ------ mutable borrow occurs here @@ -10,7 +10,7 @@ LL | *y += 1; | ------- mutable borrow later used here error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-activation-sharing-interference.rs:36:13 + --> $DIR/two-phase-activation-sharing-interference.rs:37:13 | LL | let y = &mut x; | ------ mutable borrow occurs here @@ -32,7 +32,7 @@ LL | *y += 1; | ------- mutable borrow later used here error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-activation-sharing-interference.rs:58:14 + --> $DIR/two-phase-activation-sharing-interference.rs:56:14 | LL | let y = &mut x; | ------ mutable borrow occurs here diff --git a/tests/ui/borrowck/two-phase-activation-sharing-interference.rs b/tests/ui/borrowck/two-phase-activation-sharing-interference.rs index beee9916fca2c..1b4526a13a85b 100644 --- a/tests/ui/borrowck/two-phase-activation-sharing-interference.rs +++ b/tests/ui/borrowck/two-phase-activation-sharing-interference.rs @@ -1,6 +1,7 @@ //@ revisions: nll_target // The following revisions are disabled due to missing support from two-phase beyond autorefs +//@ unused-revision-names: nll_beyond //@[nll_beyond] compile-flags: -Z two-phase-beyond-autoref // This is an important corner case pointed out by Niko: one is @@ -36,8 +37,7 @@ fn not_ok() { let z = &x; //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable *y += 1; - //[lxl_beyond]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable - //[nll_beyond]~^^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable + //[nll_beyond]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable read(z); } @@ -48,8 +48,6 @@ fn should_be_ok_with_nll() { //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable read(z); *y += 1; - //[lxl_beyond]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable - // (okay with (generalized) nll today) } fn should_also_eventually_be_ok_with_nll() { @@ -58,8 +56,6 @@ fn should_also_eventually_be_ok_with_nll() { let _z = &x; //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable *y += 1; - //[lxl_beyond]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable - // (okay with (generalized) nll today) } fn main() { } diff --git a/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr b/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr index 1356c80493cdb..b7a1de02a4f61 100644 --- a/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr +++ b/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr @@ -1,5 +1,5 @@ error[E0503]: cannot use `i` because it was mutably borrowed - --> $DIR/two-phase-allow-access-during-reservation.rs:26:19 + --> $DIR/two-phase-allow-access-during-reservation.rs:27:19 | LL | /*1*/ let p = &mut i; // (reservation of `i` starts here) | ------ `i` is borrowed here @@ -11,7 +11,7 @@ LL | /*3*/ *p += 1; // (mutable borrow of `i` starts here, since `p` | ------- borrow later used here error[E0503]: cannot use `i` because it was mutably borrowed - --> $DIR/two-phase-allow-access-during-reservation.rs:31:19 + --> $DIR/two-phase-allow-access-during-reservation.rs:32:19 | LL | /*1*/ let p = &mut i; // (reservation of `i` starts here) | ------ `i` is borrowed here diff --git a/tests/ui/borrowck/two-phase-allow-access-during-reservation.rs b/tests/ui/borrowck/two-phase-allow-access-during-reservation.rs index e6b2501c1ebde..6b5a2f5e62365 100644 --- a/tests/ui/borrowck/two-phase-allow-access-during-reservation.rs +++ b/tests/ui/borrowck/two-phase-allow-access-during-reservation.rs @@ -1,6 +1,7 @@ //@ revisions: nll_target // The following revisions are disabled due to missing support for two_phase_beyond_autoref +//@ unused-revision-names: nll_beyond //@[nll_beyond] compile-flags: -Z two_phase_beyond_autoref // This is the second counter-example from Niko's blog post diff --git a/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr b/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr index e122977b9f2e0..c9d49b8756d87 100644 --- a/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr +++ b/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `*f` as mutable more than once at a time - --> $DIR/two-phase-nonrecv-autoref.rs:50:11 + --> $DIR/two-phase-nonrecv-autoref.rs:51:11 | LL | f(f(10)); | - ^ second mutable borrow occurs here @@ -8,7 +8,7 @@ LL | f(f(10)); | first borrow later used by call error[E0382]: use of moved value: `f` - --> $DIR/two-phase-nonrecv-autoref.rs:57:11 + --> $DIR/two-phase-nonrecv-autoref.rs:58:11 | LL | fn twice_ten_so i32>(f: Box) { | - move occurs because `f` has type `Box`, which does not implement the `Copy` trait @@ -18,7 +18,7 @@ LL | f(f(10)); | value moved here error[E0499]: cannot borrow `*f` as mutable more than once at a time - --> $DIR/two-phase-nonrecv-autoref.rs:62:11 + --> $DIR/two-phase-nonrecv-autoref.rs:63:11 | LL | f(f(10)); | - ^ second mutable borrow occurs here @@ -27,7 +27,7 @@ LL | f(f(10)); | first borrow later used by call error[E0382]: use of moved value: `f` - --> $DIR/two-phase-nonrecv-autoref.rs:69:11 + --> $DIR/two-phase-nonrecv-autoref.rs:70:11 | LL | fn twice_ten_oo(f: Box i32>) { | - move occurs because `f` has type `Box i32>`, which does not implement the `Copy` trait @@ -37,7 +37,7 @@ LL | f(f(10)); | value moved here error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:107:27 + --> $DIR/two-phase-nonrecv-autoref.rs:108:27 | LL | double_access(&mut a, &a); | ------------- ------ ^^ immutable borrow occurs here @@ -46,7 +46,7 @@ LL | double_access(&mut a, &a); | mutable borrow later used by call error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:132:7 + --> $DIR/two-phase-nonrecv-autoref.rs:133:7 | LL | i[i[3]] = 4; | --^---- @@ -56,18 +56,18 @@ LL | i[i[3]] = 4; | mutable borrow occurs here | help: try adding a local storing this... - --> $DIR/two-phase-nonrecv-autoref.rs:132:8 + --> $DIR/two-phase-nonrecv-autoref.rs:133:8 | LL | i[i[3]] = 4; | ^^^ help: ...and then using that local here - --> $DIR/two-phase-nonrecv-autoref.rs:132:6 + --> $DIR/two-phase-nonrecv-autoref.rs:133:6 | LL | i[i[3]] = 4; | ^^^^^^ error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable - --> $DIR/two-phase-nonrecv-autoref.rs:138:7 + --> $DIR/two-phase-nonrecv-autoref.rs:139:7 | LL | i[i[3]] = i[4]; | --^---- @@ -77,12 +77,12 @@ LL | i[i[3]] = i[4]; | mutable borrow occurs here | help: try adding a local storing this... - --> $DIR/two-phase-nonrecv-autoref.rs:138:8 + --> $DIR/two-phase-nonrecv-autoref.rs:139:8 | LL | i[i[3]] = i[4]; | ^^^ help: ...and then using that local here - --> $DIR/two-phase-nonrecv-autoref.rs:138:6 + --> $DIR/two-phase-nonrecv-autoref.rs:139:6 | LL | i[i[3]] = i[4]; | ^^^^^^ diff --git a/tests/ui/borrowck/two-phase-nonrecv-autoref.rs b/tests/ui/borrowck/two-phase-nonrecv-autoref.rs index f52e9c2e3fdcb..3a8ab4ef3b0f4 100644 --- a/tests/ui/borrowck/two-phase-nonrecv-autoref.rs +++ b/tests/ui/borrowck/two-phase-nonrecv-autoref.rs @@ -1,5 +1,6 @@ //@ revisions: base +//@ unused-revision-names: g2p //@[g2p]compile-flags: -Z two-phase-beyond-autoref // the above revision is disabled until two-phase-beyond-autoref support is better diff --git a/tests/ui/borrowck/two-phase-reservation-sharing-interference.nll_target.stderr b/tests/ui/borrowck/two-phase-reservation-sharing-interference.nll_target.stderr index b1e4392989fee..5eda482801276 100644 --- a/tests/ui/borrowck/two-phase-reservation-sharing-interference.nll_target.stderr +++ b/tests/ui/borrowck/two-phase-reservation-sharing-interference.nll_target.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `vec` as mutable because it is also borrowed as immutable - --> $DIR/two-phase-reservation-sharing-interference.rs:32:17 + --> $DIR/two-phase-reservation-sharing-interference.rs:33:17 | LL | let shared = &vec; | ---- immutable borrow occurs here diff --git a/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs b/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs index b6bcf7b66173e..61446577db29b 100644 --- a/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs +++ b/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs @@ -1,6 +1,7 @@ //@ revisions: nll_target // The nll_beyond revision is disabled due to missing support from two-phase beyond autorefs +//@ unused-revision-names: nll_beyond //@[nll_beyond]compile-flags: -Z two-phase-beyond-autoref //@[nll_beyond]should-fail 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 c196f607376fb..755373d7b77af 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr @@ -30,7 +30,7 @@ LL | #[cfg(feature = "unk")] = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition name: `feature` - --> $DIR/exhaustive-names-values.rs:25:7 + --> $DIR/exhaustive-names-values.rs:24:7 | LL | #[cfg(feature = "std")] | ^^^^^^^^^^^^^^^ diff --git a/tests/ui/check-cfg/exhaustive-names-values.rs b/tests/ui/check-cfg/exhaustive-names-values.rs index a6190f15dbb4b..7b2d89b5781dd 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.rs +++ b/tests/ui/check-cfg/exhaustive-names-values.rs @@ -16,15 +16,13 @@ pub fn f() {} pub fn f() {} #[cfg(feature = "unk")] -//[empty_names_values]~^ WARNING unexpected `cfg` condition name -//[empty_cfg]~^^ WARNING unexpected `cfg` condition name -//[feature]~^^^ WARNING unexpected `cfg` condition value -//[full]~^^^^ WARNING unexpected `cfg` condition value +//[empty_cfg]~^ WARNING unexpected `cfg` condition name +//[feature]~^^ WARNING unexpected `cfg` condition value +//[full]~^^^ WARNING unexpected `cfg` condition value pub fn feat() {} #[cfg(feature = "std")] -//[empty_names_values]~^ WARNING unexpected `cfg` condition name -//[empty_cfg]~^^ WARNING unexpected `cfg` condition name +//[empty_cfg]~^ WARNING unexpected `cfg` condition name pub fn feat() {} #[cfg(windows)] diff --git a/tests/ui/check-cfg/invalid-arguments.any_values.stderr b/tests/ui/check-cfg/invalid-arguments.any_values.stderr index f9a9c4a6e1328..65ef5155fa1a3 100644 --- a/tests/ui/check-cfg/invalid-arguments.any_values.stderr +++ b/tests/ui/check-cfg/invalid-arguments.any_values.stderr @@ -1,2 +1,5 @@ -error: invalid `--check-cfg` argument: `cfg(any(),values())` (`values()` cannot be specified before the names) +error: invalid `--check-cfg` argument: `cfg(any(),values())` + | + = note: `values()` cannot be specified before the names + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.anything_else.stderr b/tests/ui/check-cfg/invalid-arguments.anything_else.stderr index 925664bb3fc62..f3bc0b782e22f 100644 --- a/tests/ui/check-cfg/invalid-arguments.anything_else.stderr +++ b/tests/ui/check-cfg/invalid-arguments.anything_else.stderr @@ -1,2 +1,5 @@ -error: invalid `--check-cfg` argument: `anything_else(...)` (expected `cfg(name, values("value1", "value2", ... "valueN"))`) +error: invalid `--check-cfg` argument: `anything_else(...)` + | + = note: expected `cfg(name, values("value1", "value2", ... "valueN"))` + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.boolean.stderr b/tests/ui/check-cfg/invalid-arguments.boolean.stderr new file mode 100644 index 0000000000000..18734de9dac03 --- /dev/null +++ b/tests/ui/check-cfg/invalid-arguments.boolean.stderr @@ -0,0 +1,6 @@ +error: invalid `--check-cfg` argument: `cfg(true)` + | + = note: `true` is a boolean literal + = note: `cfg()` arguments must be simple identifiers, `any()` or `values(...)` + = note: visit for more details + diff --git a/tests/ui/check-cfg/invalid-arguments.cfg_none.stderr b/tests/ui/check-cfg/invalid-arguments.cfg_none.stderr index 7992dbdff005a..ef464260c29dc 100644 --- a/tests/ui/check-cfg/invalid-arguments.cfg_none.stderr +++ b/tests/ui/check-cfg/invalid-arguments.cfg_none.stderr @@ -1,2 +1,6 @@ -error: invalid `--check-cfg` argument: `cfg(none())` (`cfg()` arguments must be simple identifiers, `any()` or `values(...)`) +error: invalid `--check-cfg` argument: `cfg(none())` + | + = note: `none()` is invalid + = note: `cfg()` arguments must be simple identifiers, `any()` or `values(...)` + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.giberich.stderr b/tests/ui/check-cfg/invalid-arguments.giberich.stderr index d427033fcc262..3e35014549183 100644 --- a/tests/ui/check-cfg/invalid-arguments.giberich.stderr +++ b/tests/ui/check-cfg/invalid-arguments.giberich.stderr @@ -1,2 +1,5 @@ -error: invalid `--check-cfg` argument: `cfg(...)` (expected `cfg(name, values("value1", "value2", ... "valueN"))`) +error: invalid `--check-cfg` argument: `cfg(...)` + | + = note: expected `cfg(name, values("value1", "value2", ... "valueN"))` + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.ident_in_values_1.stderr b/tests/ui/check-cfg/invalid-arguments.ident_in_values_1.stderr index 90308bdcd2355..cfedb7ed51743 100644 --- a/tests/ui/check-cfg/invalid-arguments.ident_in_values_1.stderr +++ b/tests/ui/check-cfg/invalid-arguments.ident_in_values_1.stderr @@ -1,2 +1,6 @@ -error: invalid `--check-cfg` argument: `cfg(foo,values(bar))` (`values()` arguments must be string literals, `none()` or `any()`) +error: invalid `--check-cfg` argument: `cfg(foo,values(bar))` + | + = note: `bar` is invalid + = note: `values()` arguments must be string literals, `none()` or `any()` + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.ident_in_values_2.stderr b/tests/ui/check-cfg/invalid-arguments.ident_in_values_2.stderr index 16f92a504a5fa..ba194862284de 100644 --- a/tests/ui/check-cfg/invalid-arguments.ident_in_values_2.stderr +++ b/tests/ui/check-cfg/invalid-arguments.ident_in_values_2.stderr @@ -1,2 +1,6 @@ -error: invalid `--check-cfg` argument: `cfg(foo,values("bar",bar,"bar"))` (`values()` arguments must be string literals, `none()` or `any()`) +error: invalid `--check-cfg` argument: `cfg(foo,values("bar",bar,"bar"))` + | + = note: `bar` is invalid + = note: `values()` arguments must be string literals, `none()` or `any()` + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.mixed_any.stderr b/tests/ui/check-cfg/invalid-arguments.mixed_any.stderr index 9239f8cce945f..512ecbe9edaf0 100644 --- a/tests/ui/check-cfg/invalid-arguments.mixed_any.stderr +++ b/tests/ui/check-cfg/invalid-arguments.mixed_any.stderr @@ -1,2 +1,5 @@ -error: invalid `--check-cfg` argument: `cfg(any(),values(any()))` (`values()` cannot be specified before the names) +error: invalid `--check-cfg` argument: `cfg(any(),values(any()))` + | + = note: `values()` cannot be specified before the names + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.mixed_values_any.stderr b/tests/ui/check-cfg/invalid-arguments.mixed_values_any.stderr index 4c406143d080c..2d59b12097d7d 100644 --- a/tests/ui/check-cfg/invalid-arguments.mixed_values_any.stderr +++ b/tests/ui/check-cfg/invalid-arguments.mixed_values_any.stderr @@ -1,2 +1,5 @@ -error: invalid `--check-cfg` argument: `cfg(foo,values("bar",any()))` (`values()` arguments cannot specify string literals and `any()` at the same time) +error: invalid `--check-cfg` argument: `cfg(foo,values("bar",any()))` + | + = note: `values()` arguments cannot specify string literals and `any()` at the same time + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.multiple_any.stderr b/tests/ui/check-cfg/invalid-arguments.multiple_any.stderr index 6f1db1b13c310..6eb63de425244 100644 --- a/tests/ui/check-cfg/invalid-arguments.multiple_any.stderr +++ b/tests/ui/check-cfg/invalid-arguments.multiple_any.stderr @@ -1,2 +1,5 @@ -error: invalid `--check-cfg` argument: `cfg(any(),any())` (`any()` cannot be specified multiple times) +error: invalid `--check-cfg` argument: `cfg(any(),any())` + | + = note: `any()` cannot be specified multiple times + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.multiple_values.stderr b/tests/ui/check-cfg/invalid-arguments.multiple_values.stderr index bce305b09c304..06060078bc025 100644 --- a/tests/ui/check-cfg/invalid-arguments.multiple_values.stderr +++ b/tests/ui/check-cfg/invalid-arguments.multiple_values.stderr @@ -1,2 +1,5 @@ -error: invalid `--check-cfg` argument: `cfg(foo,values(),values())` (`values()` cannot be specified multiple times) +error: invalid `--check-cfg` argument: `cfg(foo,values(),values())` + | + = note: `values()` cannot be specified multiple times + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.multiple_values_any.stderr b/tests/ui/check-cfg/invalid-arguments.multiple_values_any.stderr index 748ce231af73d..72554ac3ead84 100644 --- a/tests/ui/check-cfg/invalid-arguments.multiple_values_any.stderr +++ b/tests/ui/check-cfg/invalid-arguments.multiple_values_any.stderr @@ -1,2 +1,6 @@ -error: invalid `--check-cfg` argument: `cfg(foo,values(any(),any()))` (`any()` in `values()` cannot be specified multiple times) +error: invalid `--check-cfg` argument: `cfg(foo,values(any(),any()))` + | + = note: `any()` is invalid + = note: `any()` in `values()` cannot be specified multiple times + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.none_not_empty.stderr b/tests/ui/check-cfg/invalid-arguments.none_not_empty.stderr index 0a6c6ffd42f2c..6e9d87bace2f2 100644 --- a/tests/ui/check-cfg/invalid-arguments.none_not_empty.stderr +++ b/tests/ui/check-cfg/invalid-arguments.none_not_empty.stderr @@ -1,2 +1,6 @@ -error: invalid `--check-cfg` argument: `cfg(foo,values(none("test")))` (`none()` must be empty) +error: invalid `--check-cfg` argument: `cfg(foo,values(none("test")))` + | + = note: `none("test")` is invalid + = note: `none()` in `values()` takes no argument + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.not_empty_any.stderr b/tests/ui/check-cfg/invalid-arguments.not_empty_any.stderr index daf38147fe53c..35eb1949ad7c8 100644 --- a/tests/ui/check-cfg/invalid-arguments.not_empty_any.stderr +++ b/tests/ui/check-cfg/invalid-arguments.not_empty_any.stderr @@ -1,2 +1,6 @@ -error: invalid `--check-cfg` argument: `cfg(any(foo))` (`any()` must be empty) +error: invalid `--check-cfg` argument: `cfg(any(foo))` + | + = note: `any(foo)` is invalid + = note: `any()` takes no argument + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.not_empty_values_any.stderr b/tests/ui/check-cfg/invalid-arguments.not_empty_values_any.stderr index 79f83e802ca55..cc41d21bec6e3 100644 --- a/tests/ui/check-cfg/invalid-arguments.not_empty_values_any.stderr +++ b/tests/ui/check-cfg/invalid-arguments.not_empty_values_any.stderr @@ -1,2 +1,6 @@ -error: invalid `--check-cfg` argument: `cfg(foo,values(any(bar)))` (`any()` must be empty) +error: invalid `--check-cfg` argument: `cfg(foo,values(any(bar)))` + | + = note: `any(bar)` is invalid + = note: `any()` in `values()` takes no argument + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.rs b/tests/ui/check-cfg/invalid-arguments.rs index c0b58ede97f40..b8588ecb4ff68 100644 --- a/tests/ui/check-cfg/invalid-arguments.rs +++ b/tests/ui/check-cfg/invalid-arguments.rs @@ -2,7 +2,7 @@ // //@ check-fail //@ no-auto-check-cfg -//@ revisions: anything_else +//@ revisions: anything_else boolean //@ revisions: string_for_name_1 string_for_name_2 multiple_any multiple_values //@ revisions: multiple_values_any not_empty_any not_empty_values_any //@ revisions: values_any_missing_values values_any_before_ident ident_in_values_1 @@ -11,6 +11,7 @@ //@ revisions: none_not_empty cfg_none // //@ [anything_else]compile-flags: --check-cfg=anything_else(...) +//@ [boolean]compile-flags: --check-cfg=cfg(true) //@ [string_for_name_1]compile-flags: --check-cfg=cfg("NOT_IDENT") //@ [string_for_name_2]compile-flags: --check-cfg=cfg(foo,"NOT_IDENT",bar) //@ [multiple_any]compile-flags: --check-cfg=cfg(any(),any()) diff --git a/tests/ui/check-cfg/invalid-arguments.string_for_name_1.stderr b/tests/ui/check-cfg/invalid-arguments.string_for_name_1.stderr index c6f6834ffd307..7022b709b64a2 100644 --- a/tests/ui/check-cfg/invalid-arguments.string_for_name_1.stderr +++ b/tests/ui/check-cfg/invalid-arguments.string_for_name_1.stderr @@ -1,2 +1,6 @@ -error: invalid `--check-cfg` argument: `cfg("NOT_IDENT")` (`cfg()` arguments must be simple identifiers, `any()` or `values(...)`) +error: invalid `--check-cfg` argument: `cfg("NOT_IDENT")` + | + = note: `"NOT_IDENT"` is a string literal + = note: `cfg()` arguments must be simple identifiers, `any()` or `values(...)` + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.string_for_name_2.stderr b/tests/ui/check-cfg/invalid-arguments.string_for_name_2.stderr index ab3dc86cd1ad8..ea96b913907a9 100644 --- a/tests/ui/check-cfg/invalid-arguments.string_for_name_2.stderr +++ b/tests/ui/check-cfg/invalid-arguments.string_for_name_2.stderr @@ -1,2 +1,6 @@ -error: invalid `--check-cfg` argument: `cfg(foo,"NOT_IDENT",bar)` (`cfg()` arguments must be simple identifiers, `any()` or `values(...)`) +error: invalid `--check-cfg` argument: `cfg(foo,"NOT_IDENT",bar)` + | + = note: `"NOT_IDENT"` is a string literal + = note: `cfg()` arguments must be simple identifiers, `any()` or `values(...)` + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_1.stderr b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_1.stderr index c04b15ec265c1..f82c520c62a6e 100644 --- a/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_1.stderr +++ b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_1.stderr @@ -1,2 +1,5 @@ -error: invalid `--check-cfg` argument: `abc()` (expected `cfg(name, values("value1", "value2", ... "valueN"))`) +error: invalid `--check-cfg` argument: `abc()` + | + = note: expected `cfg(name, values("value1", "value2", ... "valueN"))` + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_2.stderr b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_2.stderr index cee65f9887b9a..ee62c25b41cb4 100644 --- a/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_2.stderr +++ b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_2.stderr @@ -1,2 +1,6 @@ -error: invalid `--check-cfg` argument: `cfg(foo,test())` (`cfg()` arguments must be simple identifiers, `any()` or `values(...)`) +error: invalid `--check-cfg` argument: `cfg(foo,test())` + | + = note: `test()` is invalid + = note: `cfg()` arguments must be simple identifiers, `any()` or `values(...)` + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_3.stderr b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_3.stderr index a023779b35a7b..a8ab9cc9d303f 100644 --- a/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_3.stderr +++ b/tests/ui/check-cfg/invalid-arguments.unknown_meta_item_3.stderr @@ -1,2 +1,6 @@ -error: invalid `--check-cfg` argument: `cfg(foo,values(test()))` (`values()` arguments must be string literals, `none()` or `any()`) +error: invalid `--check-cfg` argument: `cfg(foo,values(test()))` + | + = note: `test()` is invalid + = note: `values()` arguments must be string literals, `none()` or `any()` + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.unterminated.stderr b/tests/ui/check-cfg/invalid-arguments.unterminated.stderr index 80161a6aa0fc8..150e1d66426b9 100644 --- a/tests/ui/check-cfg/invalid-arguments.unterminated.stderr +++ b/tests/ui/check-cfg/invalid-arguments.unterminated.stderr @@ -1,2 +1,5 @@ -error: invalid `--check-cfg` argument: `cfg(` (expected `cfg(name, values("value1", "value2", ... "valueN"))`) +error: invalid `--check-cfg` argument: `cfg(` + | + = note: expected `cfg(name, values("value1", "value2", ... "valueN"))` + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.values_any_before_ident.stderr b/tests/ui/check-cfg/invalid-arguments.values_any_before_ident.stderr index fc93ec8fbdfd5..7013bb8e0951d 100644 --- a/tests/ui/check-cfg/invalid-arguments.values_any_before_ident.stderr +++ b/tests/ui/check-cfg/invalid-arguments.values_any_before_ident.stderr @@ -1,2 +1,5 @@ -error: invalid `--check-cfg` argument: `cfg(values(any()),foo)` (`values()` cannot be specified before the names) +error: invalid `--check-cfg` argument: `cfg(values(any()),foo)` + | + = note: `values()` cannot be specified before the names + = note: visit for more details diff --git a/tests/ui/check-cfg/invalid-arguments.values_any_missing_values.stderr b/tests/ui/check-cfg/invalid-arguments.values_any_missing_values.stderr index f41672fcbdb6a..ad1af73c69012 100644 --- a/tests/ui/check-cfg/invalid-arguments.values_any_missing_values.stderr +++ b/tests/ui/check-cfg/invalid-arguments.values_any_missing_values.stderr @@ -1,2 +1,5 @@ -error: invalid `--check-cfg` argument: `cfg(foo,any())` (`cfg(any())` can only be provided in isolation) +error: invalid `--check-cfg` argument: `cfg(foo,any())` + | + = note: `cfg(any())` can only be provided in isolation + = note: visit for more details diff --git a/tests/ui/check-cfg/values-none.concat_1.stderr b/tests/ui/check-cfg/values-none.concat_1.stderr new file mode 100644 index 0000000000000..b8f0b02b4c563 --- /dev/null +++ b/tests/ui/check-cfg/values-none.concat_1.stderr @@ -0,0 +1,13 @@ +warning: unexpected `cfg` condition value: `bar` + --> $DIR/values-none.rs:16:7 + | +LL | #[cfg(foo = "bar")] + | ^^^^^^^^^^^ + | + = note: expected values for `foo` are: (none), `too` + = help: to expect this configuration use `--check-cfg=cfg(foo, values("bar"))` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/check-cfg/values-none.concat_2.stderr b/tests/ui/check-cfg/values-none.concat_2.stderr new file mode 100644 index 0000000000000..b8f0b02b4c563 --- /dev/null +++ b/tests/ui/check-cfg/values-none.concat_2.stderr @@ -0,0 +1,13 @@ +warning: unexpected `cfg` condition value: `bar` + --> $DIR/values-none.rs:16:7 + | +LL | #[cfg(foo = "bar")] + | ^^^^^^^^^^^ + | + = note: expected values for `foo` are: (none), `too` + = help: to expect this configuration use `--check-cfg=cfg(foo, values("bar"))` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/check-cfg/values-none.rs b/tests/ui/check-cfg/values-none.rs index 6856d2f33af07..447fde2bfcce0 100644 --- a/tests/ui/check-cfg/values-none.rs +++ b/tests/ui/check-cfg/values-none.rs @@ -1,7 +1,7 @@ //@ check-pass // //@ no-auto-check-cfg -//@ revisions: explicit implicit +//@ revisions: explicit implicit simple concat_1 concat_2 //@ [explicit]compile-flags: --check-cfg=cfg(foo,values(none())) //@ [implicit]compile-flags: --check-cfg=cfg(foo) //@ [simple] compile-flags: --check-cfg=cfg(foo,values(none(),"too")) diff --git a/tests/ui/check-cfg/values-none.simple.stderr b/tests/ui/check-cfg/values-none.simple.stderr new file mode 100644 index 0000000000000..b8f0b02b4c563 --- /dev/null +++ b/tests/ui/check-cfg/values-none.simple.stderr @@ -0,0 +1,13 @@ +warning: unexpected `cfg` condition value: `bar` + --> $DIR/values-none.rs:16:7 + | +LL | #[cfg(foo = "bar")] + | ^^^^^^^^^^^ + | + = note: expected values for `foo` are: (none), `too` + = help: to expect this configuration use `--check-cfg=cfg(foo, values("bar"))` + = note: see for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs index 408eaffccf7d9..d885281249203 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs @@ -28,8 +28,8 @@ struct S9; macro_rules! generate_s10 { ($expr: expr) => { #[cfg(feature = $expr)] - //~^ ERROR expected unsuffixed literal or identifier, found `concat!("nonexistent")` - //~| ERROR expected unsuffixed literal or identifier, found `concat!("nonexistent")` + //~^ ERROR expected unsuffixed literal, found `concat!("nonexistent")` + //~| ERROR expected unsuffixed literal, found `concat!("nonexistent")` struct S10; } } diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr index 12557ff636041..3dd0823389cde 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr @@ -54,7 +54,7 @@ LL | #[cfg(a = b"hi")] | | | help: consider removing the prefix -error: expected unsuffixed literal or identifier, found `concat!("nonexistent")` +error: expected unsuffixed literal, found `concat!("nonexistent")` --> $DIR/cfg-attr-syntax-validation.rs:30:25 | LL | #[cfg(feature = $expr)] @@ -65,7 +65,7 @@ LL | generate_s10!(concat!("nonexistent")); | = note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected unsuffixed literal or identifier, found `concat!("nonexistent")` +error: expected unsuffixed literal, found `concat!("nonexistent")` --> $DIR/cfg-attr-syntax-validation.rs:30:25 | LL | #[cfg(feature = $expr)] diff --git a/tests/ui/consts/offset_from_ub.rs b/tests/ui/consts/offset_from_ub.rs index 51163e650d6aa..e0dd27079156f 100644 --- a/tests/ui/consts/offset_from_ub.rs +++ b/tests/ui/consts/offset_from_ub.rs @@ -42,7 +42,7 @@ pub const DIFFERENT_INT: isize = { // offset_from with two different integers: l let ptr1 = 8 as *const u8; let ptr2 = 16 as *const u8; unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed - //~| 0x8[noalloc] is a dangling pointer + //~| different pointers without provenance }; const OUT_OF_BOUNDS_1: isize = { @@ -81,13 +81,13 @@ pub const DIFFERENT_ALLOC_UNSIGNED: usize = { }; pub const TOO_FAR_APART1: isize = { - let ptr1 = ptr::null::(); + let ptr1 = &0u8 as *const u8; let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42); unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed //~| too far ahead }; pub const TOO_FAR_APART2: isize = { - let ptr1 = ptr::null::(); + let ptr1 = &0u8 as *const u8; let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42); unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed //~| too far before @@ -100,7 +100,7 @@ const WRONG_ORDER_UNSIGNED: usize = { //~| first pointer has smaller offset than second: 0 < 8 }; pub const TOO_FAR_APART_UNSIGNED: usize = { - let ptr1 = ptr::null::(); + let ptr1 = &0u8 as *const u8; let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42); // This would fit into a `usize` but we still don't allow it. unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } //~ERROR evaluation of constant value failed diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr index 4fbb2f00100a6..e3bac8d5e31ad 100644 --- a/tests/ui/consts/offset_from_ub.stderr +++ b/tests/ui/consts/offset_from_ub.stderr @@ -33,7 +33,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:44:14 | LL | unsafe { ptr_offset_from(ptr2, ptr1) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: 0x8[noalloc] is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation) error[E0080]: evaluation of constant value failed --> $DIR/offset_from_ub.rs:53:14 @@ -86,7 +86,7 @@ LL | unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: out-of-bounds `offset_from`: null pointer is a dangling pointer (it has no provenance) + = note: `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation) | note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -99,7 +99,7 @@ LL | unsafe { ptr2.offset_from(ptr1) } error[E0080]: evaluation of constant value failed --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | - = note: out-of-bounds `offset_from`: null pointer is a dangling pointer (it has no provenance) + = note: `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation) | note: inside `std::ptr::const_ptr::::offset_from` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL diff --git a/tests/ui/coroutine/break-inside-coroutine-issue-124495.rs b/tests/ui/coroutine/break-inside-coroutine-issue-124495.rs new file mode 100644 index 0000000000000..5d93db56722bf --- /dev/null +++ b/tests/ui/coroutine/break-inside-coroutine-issue-124495.rs @@ -0,0 +1,26 @@ +//@ edition: 2024 +//@ compile-flags: -Z unstable-options + +#![feature(gen_blocks)] +#![feature(async_closure)] + +async fn async_fn() { + break; //~ ERROR `break` inside `async` function +} + +gen fn gen_fn() { + break; //~ ERROR `break` inside `gen` function +} + +async gen fn async_gen_fn() { + break; //~ ERROR `break` inside `async gen` function +} + +fn main() { + let _ = async { break; }; //~ ERROR `break` inside `async` block + let _ = async || { break; }; //~ ERROR `break` inside `async` closure + + let _ = gen { break; }; //~ ERROR `break` inside `gen` block + + let _ = async gen { break; }; //~ ERROR `break` inside `async gen` block +} diff --git a/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr b/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr new file mode 100644 index 0000000000000..a7f37fad35ea8 --- /dev/null +++ b/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr @@ -0,0 +1,69 @@ +error[E0267]: `break` inside `async` function + --> $DIR/break-inside-coroutine-issue-124495.rs:8:5 + | +LL | async fn async_fn() { + | _____________________- +LL | | break; + | | ^^^^^ cannot `break` inside `async` function +LL | | } + | |_- enclosing `async` function + +error[E0267]: `break` inside `gen` function + --> $DIR/break-inside-coroutine-issue-124495.rs:12:5 + | +LL | gen fn gen_fn() { + | _________________- +LL | | break; + | | ^^^^^ cannot `break` inside `gen` function +LL | | } + | |_- enclosing `gen` function + +error[E0267]: `break` inside `async gen` function + --> $DIR/break-inside-coroutine-issue-124495.rs:16:5 + | +LL | async gen fn async_gen_fn() { + | _____________________________- +LL | | break; + | | ^^^^^ cannot `break` inside `async gen` function +LL | | } + | |_- enclosing `async gen` function + +error[E0267]: `break` inside `async` block + --> $DIR/break-inside-coroutine-issue-124495.rs:20:21 + | +LL | let _ = async { break; }; + | --------^^^^^--- + | | | + | | cannot `break` inside `async` block + | enclosing `async` block + +error[E0267]: `break` inside `async` closure + --> $DIR/break-inside-coroutine-issue-124495.rs:21:24 + | +LL | let _ = async || { break; }; + | --^^^^^--- + | | | + | | cannot `break` inside `async` closure + | enclosing `async` closure + +error[E0267]: `break` inside `gen` block + --> $DIR/break-inside-coroutine-issue-124495.rs:23:19 + | +LL | let _ = gen { break; }; + | ------^^^^^--- + | | | + | | cannot `break` inside `gen` block + | enclosing `gen` block + +error[E0267]: `break` inside `async gen` block + --> $DIR/break-inside-coroutine-issue-124495.rs:25:25 + | +LL | let _ = async gen { break; }; + | ------------^^^^^--- + | | | + | | cannot `break` inside `async gen` block + | enclosing `async gen` block + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0267`. diff --git a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr index 078c766deedd2..a030da5068c2d 100644 --- a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr +++ b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr @@ -4,7 +4,7 @@ error: expected unsuffixed literal, found `test` LL | #[deprecated(note = test)] | ^^^^ | -help: surround the identifier with quotation marks to parse it as a string +help: surround the identifier with quotation marks to make it into a string literal | LL | #[deprecated(note = "test")] | + + diff --git a/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr b/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr index d0b14ef94c17b..e88a523ef4f17 100644 --- a/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr +++ b/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr @@ -1,4 +1,4 @@ -error[E0369]: binary operation `==` cannot be applied to type `Error` +error[E0369]: binary operation `==` cannot be applied to type `&Error` --> $DIR/derives-span-PartialEq-enum-struct-variant.rs:9:6 | LL | #[derive(PartialEq)] diff --git a/tests/ui/derives/derives-span-PartialEq-enum.stderr b/tests/ui/derives/derives-span-PartialEq-enum.stderr index f69451ac793ee..80b225446b47d 100644 --- a/tests/ui/derives/derives-span-PartialEq-enum.stderr +++ b/tests/ui/derives/derives-span-PartialEq-enum.stderr @@ -1,4 +1,4 @@ -error[E0369]: binary operation `==` cannot be applied to type `Error` +error[E0369]: binary operation `==` cannot be applied to type `&Error` --> $DIR/derives-span-PartialEq-enum.rs:9:6 | LL | #[derive(PartialEq)] diff --git a/tests/ui/deriving/deriving-all-codegen.rs b/tests/ui/deriving/deriving-all-codegen.rs index 498930fc0c664..6fa4f74f2a508 100644 --- a/tests/ui/deriving/deriving-all-codegen.rs +++ b/tests/ui/deriving/deriving-all-codegen.rs @@ -156,6 +156,20 @@ enum EnumGeneric { Two(U), } +// An enum that has variant, which does't implement `Copy`. +#[derive(PartialEq)] +enum NonCopyEnum { + // The `dyn NonCopyTrait` implements `PartialEq`, but it doesn't require `Copy`. + // So we cannot generate `PartialEq` with dereference. + NonCopyField(Box), +} +trait NonCopyTrait {} +impl PartialEq for dyn NonCopyTrait { + fn eq(&self, _other: &Self) -> bool { + true + } +} + // A union. Most builtin traits are not derivable for unions. #[derive(Clone, Copy)] pub union Union { diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout index 9f8a9f30ff682..6b69b57c51619 100644 --- a/tests/ui/deriving/deriving-all-codegen.stdout +++ b/tests/ui/deriving/deriving-all-codegen.stdout @@ -876,7 +876,7 @@ impl ::core::cmp::PartialEq for Enum1 { fn eq(&self, other: &Enum1) -> bool { match (self, other) { (Enum1::Single { x: __self_0 }, Enum1::Single { x: __arg1_0 }) => - *__self_0 == *__arg1_0, + __self_0 == __arg1_0, } } } @@ -1119,10 +1119,10 @@ impl ::core::cmp::PartialEq for Mixed { __self_discr == __arg1_discr && match (self, other) { (Mixed::R(__self_0), Mixed::R(__arg1_0)) => - *__self_0 == *__arg1_0, + __self_0 == __arg1_0, (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S { d1: __arg1_0, d2: __arg1_1 }) => - *__self_0 == *__arg1_0 && *__self_1 == *__arg1_1, + __self_0 == __arg1_0 && __self_1 == __arg1_1, _ => true, } } @@ -1245,11 +1245,11 @@ impl ::core::cmp::PartialEq for Fielded { __self_discr == __arg1_discr && match (self, other) { (Fielded::X(__self_0), Fielded::X(__arg1_0)) => - *__self_0 == *__arg1_0, + __self_0 == __arg1_0, (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) => - *__self_0 == *__arg1_0, + __self_0 == __arg1_0, (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) => - *__self_0 == *__arg1_0, + __self_0 == __arg1_0, _ => unsafe { ::core::intrinsics::unreachable() } } } @@ -1368,9 +1368,9 @@ impl __self_discr == __arg1_discr && match (self, other) { (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) => - *__self_0 == *__arg1_0, + __self_0 == __arg1_0, (EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) => - *__self_0 == *__arg1_0, + __self_0 == __arg1_0, _ => unsafe { ::core::intrinsics::unreachable() } } } @@ -1426,6 +1426,30 @@ impl ::core::cmp::Ord for } } +// An enum that has variant, which does't implement `Copy`. +enum NonCopyEnum { + + // The `dyn NonCopyTrait` implements `PartialEq`, but it doesn't require `Copy`. + // So we cannot generate `PartialEq` with dereference. + NonCopyField(Box), +} +#[automatically_derived] +impl ::core::marker::StructuralPartialEq for NonCopyEnum { } +#[automatically_derived] +impl ::core::cmp::PartialEq for NonCopyEnum { + #[inline] + fn eq(&self, other: &NonCopyEnum) -> bool { + match (self, other) { + (NonCopyEnum::NonCopyField(__self_0), + NonCopyEnum::NonCopyField(__arg1_0)) => __self_0 == __arg1_0, + } + } +} +trait NonCopyTrait {} +impl PartialEq for dyn NonCopyTrait { + fn eq(&self, _other: &Self) -> bool { true } +} + // A union. Most builtin traits are not derivable for unions. pub union Union { pub b: bool, diff --git a/tests/ui/diagnostic_namespace/auxiliary/bad_on_unimplemented.rs b/tests/ui/diagnostic_namespace/auxiliary/bad_on_unimplemented.rs new file mode 100644 index 0000000000000..e44c7e4e8501a --- /dev/null +++ b/tests/ui/diagnostic_namespace/auxiliary/bad_on_unimplemented.rs @@ -0,0 +1,26 @@ +#[diagnostic::on_unimplemented(aa = "broken")] +pub trait MissingAttr {} + +#[diagnostic::on_unimplemented(label = "a", label = "b")] +pub trait DuplicateAttr {} + +#[diagnostic::on_unimplemented = "broken"] +pub trait NotMetaList {} + +#[diagnostic::on_unimplemented] +pub trait Empty {} + +#[diagnostic::on_unimplemented {}] +pub trait WrongDelim {} + +#[diagnostic::on_unimplemented(label = "{A:.3}")] +pub trait BadFormatter {} + +#[diagnostic::on_unimplemented(label = "test {}")] +pub trait NoImplicitArgs {} + +#[diagnostic::on_unimplemented(label = "{missing}")] +pub trait MissingArg {} + +#[diagnostic::on_unimplemented(label = "{_}")] +pub trait BadArg {} diff --git a/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs new file mode 100644 index 0000000000000..8b7467a17d0b4 --- /dev/null +++ b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs @@ -0,0 +1,31 @@ +//@ edition:2021 +//@ aux-build:bad_on_unimplemented.rs + +// Do not ICE when encountering a malformed `#[diagnostic::on_unimplemented]` annotation in a +// dependency when incorrectly used (#124651). + +extern crate bad_on_unimplemented; + +use bad_on_unimplemented::*; + +fn missing_attr(_: T) {} +fn duplicate_attr(_: T) {} +fn not_meta_list(_: T) {} +fn empty(_: T) {} +fn wrong_delim(_: T) {} +fn bad_formatter>(_: T) {} +fn no_implicit_args(_: T) {} +fn missing_arg(_: T) {} +fn bad_arg(_: T) {} + +fn main() { + missing_attr(()); //~ ERROR E0277 + duplicate_attr(()); //~ ERROR E0277 + not_meta_list(()); //~ ERROR E0277 + empty(()); //~ ERROR E0277 + wrong_delim(()); //~ ERROR E0277 + bad_formatter(()); //~ ERROR E0277 + no_implicit_args(()); //~ ERROR E0277 + missing_arg(()); //~ ERROR E0277 + bad_arg(()); //~ ERROR E0277 +} diff --git a/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr new file mode 100644 index 0000000000000..c3e56550b705c --- /dev/null +++ b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr @@ -0,0 +1,134 @@ +error[E0277]: the trait bound `(): bad_on_unimplemented::MissingAttr` is not satisfied + --> $DIR/malformed_foreign_on_unimplemented.rs:22:18 + | +LL | missing_attr(()); + | ------------ ^^ the trait `bad_on_unimplemented::MissingAttr` is not implemented for `()` + | | + | required by a bound introduced by this call + | +note: required by a bound in `missing_attr` + --> $DIR/malformed_foreign_on_unimplemented.rs:11:20 + | +LL | fn missing_attr(_: T) {} + | ^^^^^^^^^^^ required by this bound in `missing_attr` + +error[E0277]: the trait bound `(): bad_on_unimplemented::DuplicateAttr` is not satisfied + --> $DIR/malformed_foreign_on_unimplemented.rs:23:20 + | +LL | duplicate_attr(()); + | -------------- ^^ a + | | + | required by a bound introduced by this call + | + = help: the trait `bad_on_unimplemented::DuplicateAttr` is not implemented for `()` +note: required by a bound in `duplicate_attr` + --> $DIR/malformed_foreign_on_unimplemented.rs:12:22 + | +LL | fn duplicate_attr(_: T) {} + | ^^^^^^^^^^^^^ required by this bound in `duplicate_attr` + +error[E0277]: the trait bound `(): bad_on_unimplemented::NotMetaList` is not satisfied + --> $DIR/malformed_foreign_on_unimplemented.rs:24:19 + | +LL | not_meta_list(()); + | ------------- ^^ the trait `bad_on_unimplemented::NotMetaList` is not implemented for `()` + | | + | required by a bound introduced by this call + | +note: required by a bound in `not_meta_list` + --> $DIR/malformed_foreign_on_unimplemented.rs:13:21 + | +LL | fn not_meta_list(_: T) {} + | ^^^^^^^^^^^ required by this bound in `not_meta_list` + +error[E0277]: the trait bound `(): bad_on_unimplemented::Empty` is not satisfied + --> $DIR/malformed_foreign_on_unimplemented.rs:25:11 + | +LL | empty(()); + | ----- ^^ the trait `bad_on_unimplemented::Empty` is not implemented for `()` + | | + | required by a bound introduced by this call + | +note: required by a bound in `empty` + --> $DIR/malformed_foreign_on_unimplemented.rs:14:13 + | +LL | fn empty(_: T) {} + | ^^^^^ required by this bound in `empty` + +error[E0277]: the trait bound `(): bad_on_unimplemented::WrongDelim` is not satisfied + --> $DIR/malformed_foreign_on_unimplemented.rs:26:17 + | +LL | wrong_delim(()); + | ----------- ^^ the trait `bad_on_unimplemented::WrongDelim` is not implemented for `()` + | | + | required by a bound introduced by this call + | +note: required by a bound in `wrong_delim` + --> $DIR/malformed_foreign_on_unimplemented.rs:15:19 + | +LL | fn wrong_delim(_: T) {} + | ^^^^^^^^^^ required by this bound in `wrong_delim` + +error[E0277]: the trait bound `(): bad_on_unimplemented::BadFormatter<()>` is not satisfied + --> $DIR/malformed_foreign_on_unimplemented.rs:27:19 + | +LL | bad_formatter(()); + | ------------- ^^ () + | | + | required by a bound introduced by this call + | + = help: the trait `bad_on_unimplemented::BadFormatter<()>` is not implemented for `()` +note: required by a bound in `bad_formatter` + --> $DIR/malformed_foreign_on_unimplemented.rs:16:21 + | +LL | fn bad_formatter>(_: T) {} + | ^^^^^^^^^^^^^^^^ required by this bound in `bad_formatter` + +error[E0277]: the trait bound `(): bad_on_unimplemented::NoImplicitArgs` is not satisfied + --> $DIR/malformed_foreign_on_unimplemented.rs:28:22 + | +LL | no_implicit_args(()); + | ---------------- ^^ test {} + | | + | required by a bound introduced by this call + | + = help: the trait `bad_on_unimplemented::NoImplicitArgs` is not implemented for `()` +note: required by a bound in `no_implicit_args` + --> $DIR/malformed_foreign_on_unimplemented.rs:17:24 + | +LL | fn no_implicit_args(_: T) {} + | ^^^^^^^^^^^^^^ required by this bound in `no_implicit_args` + +error[E0277]: the trait bound `(): bad_on_unimplemented::MissingArg` is not satisfied + --> $DIR/malformed_foreign_on_unimplemented.rs:29:17 + | +LL | missing_arg(()); + | ----------- ^^ {missing} + | | + | required by a bound introduced by this call + | + = help: the trait `bad_on_unimplemented::MissingArg` is not implemented for `()` +note: required by a bound in `missing_arg` + --> $DIR/malformed_foreign_on_unimplemented.rs:18:19 + | +LL | fn missing_arg(_: T) {} + | ^^^^^^^^^^ required by this bound in `missing_arg` + +error[E0277]: the trait bound `(): bad_on_unimplemented::BadArg` is not satisfied + --> $DIR/malformed_foreign_on_unimplemented.rs:30:13 + | +LL | bad_arg(()); + | ------- ^^ {_} + | | + | required by a bound introduced by this call + | + = help: the trait `bad_on_unimplemented::BadArg` is not implemented for `()` +note: required by a bound in `bad_arg` + --> $DIR/malformed_foreign_on_unimplemented.rs:19:15 + | +LL | fn bad_arg(_: T) {} + | ^^^^^^ required by this bound in `bad_arg` + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/dyn-star/param-env-region-infer.current.stderr b/tests/ui/dyn-star/param-env-region-infer.current.stderr index b50117c1efb40..6e464c17014cc 100644 --- a/tests/ui/dyn-star/param-env-region-infer.current.stderr +++ b/tests/ui/dyn-star/param-env-region-infer.current.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/param-env-region-infer.rs:19:10 + --> $DIR/param-env-region-infer.rs:20:10 | LL | t as _ | ^ cannot infer type diff --git a/tests/ui/dyn-star/param-env-region-infer.rs b/tests/ui/dyn-star/param-env-region-infer.rs index c53861065c7da..842964ad284cc 100644 --- a/tests/ui/dyn-star/param-env-region-infer.rs +++ b/tests/ui/dyn-star/param-env-region-infer.rs @@ -1,9 +1,10 @@ //@ revisions: current //@ incremental -// FIXME(-Znext-solver): THis currently results in unstable query results: +// FIXME(-Znext-solver): This currently results in unstable query results: // `normalizes-to(opaque, opaque)` changes from `Maybe(Ambiguous)` to `Maybe(Overflow)` // once the hidden type of the opaque is already defined to be itself. +//@ unused-revision-names: next // checks that we don't ICE if there are region inference variables in the environment // when computing `PointerLike` builtin candidates. diff --git a/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr index f8bed86ccf599..a26c617dc931d 100644 --- a/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr +++ b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr @@ -1,19 +1,33 @@ error: implementation of `Trait` is not general enough --> $DIR/issue-59311.rs:17:5 | -LL | v.t(|| {}); - | ^^^^^^^^^^ implementation of `Trait` is not general enough +LL | / pub fn crash(v: &V) +LL | | where +LL | | for<'a> &'a V: Trait + 'static, + | |____________________-----__________- due to a where-clause on `crash`... + | | + | doesn't satisfy where-clause +LL | { +LL | v.t(|| {}); + | ^^^^^^^^^^ | - = note: `Trait` would have to be implemented for the type `&'a V` + = note: ...`Trait` would have to be implemented for the type `&'a V` = note: ...but `Trait` is actually implemented for the type `&'0 V`, for some specific lifetime `'0` error: implementation of `Trait` is not general enough --> $DIR/issue-59311.rs:17:5 | -LL | v.t(|| {}); - | ^^^^^^^^^^ implementation of `Trait` is not general enough +LL | / pub fn crash(v: &V) +LL | | where +LL | | for<'a> &'a V: Trait + 'static, + | |____________________-----__________- due to a where-clause on `crash`... + | | + | doesn't satisfy where-clause +LL | { +LL | v.t(|| {}); + | ^^^^^^^^^^ | - = note: `Trait` would have to be implemented for the type `&'a V` + = note: ...`Trait` would have to be implemented for the type `&'a V` = note: ...but `Trait` is actually implemented for the type `&'0 V`, for some specific lifetime `'0` = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.rs b/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.rs new file mode 100644 index 0000000000000..fa76686cc8b61 --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.rs @@ -0,0 +1,11 @@ +// Minimized test from #59311. + +pub fn crash() +where + for<'a> &'a (): 'static, +{ + || {}; + //~^ ERROR higher-ranked lifetime error +} + +fn main() {} diff --git a/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.stderr b/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.stderr new file mode 100644 index 0000000000000..9e0d7e4b7be09 --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.stderr @@ -0,0 +1,10 @@ +error: higher-ranked lifetime error + --> $DIR/trivial-does-not-hold.rs:7:5 + | +LL | || {}; + | ^^^^^ + | + = note: could not prove `for<'a> &'a (): 'b` + +error: aborting due to 1 previous error + diff --git a/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs b/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs index 2dc19b9ad6884..e9706b656f228 100644 --- a/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs +++ b/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs @@ -2,6 +2,9 @@ // when there are multiple inputs. The `dyn Bar` should default to `+ // 'static`. This used to erroneously generate an error (cc #62517). // +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) //@ check-pass trait Foo { diff --git a/tests/ui/impl-trait/in-trait/placeholder-implied-bounds.rs b/tests/ui/impl-trait/in-trait/placeholder-implied-bounds.rs index f7546a05bfdb6..df03150e29acb 100644 --- a/tests/ui/impl-trait/in-trait/placeholder-implied-bounds.rs +++ b/tests/ui/impl-trait/in-trait/placeholder-implied-bounds.rs @@ -1,3 +1,6 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) //@ check-pass pub fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-105826.rs b/tests/ui/impl-trait/issues/issue-105826.rs index e3488140dcc7a..33c5ed5fdebe5 100644 --- a/tests/ui/impl-trait/issues/issue-105826.rs +++ b/tests/ui/impl-trait/issues/issue-105826.rs @@ -1,3 +1,6 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) //@ check-pass use std::io::Write; diff --git a/tests/ui/instrument-coverage/coverage-options.rs b/tests/ui/instrument-coverage/coverage-options.rs index 332da32e435dc..2a80ce4ab2e91 100644 --- a/tests/ui/instrument-coverage/coverage-options.rs +++ b/tests/ui/instrument-coverage/coverage-options.rs @@ -1,5 +1,5 @@ //@ needs-profiler-support -//@ revisions: block branch bad +//@ revisions: block branch mcdc bad //@ compile-flags -Cinstrument-coverage //@ [block] check-pass diff --git a/tests/ui/lint/lint-unnecessary-parens.fixed b/tests/ui/lint/lint-unnecessary-parens.fixed index 973bbd70f257f..760897c5143f1 100644 --- a/tests/ui/lint/lint-unnecessary-parens.fixed +++ b/tests/ui/lint/lint-unnecessary-parens.fixed @@ -46,6 +46,28 @@ pub fn parens_with_keyword(e: &[()]) -> i32 { macro_rules! baz { ($($foo:expr),+) => { ($($foo),*) + }; +} + +macro_rules! unit { + () => { + () + }; +} + +struct One; + +impl std::ops::Sub for () { + type Output = i32; + fn sub(self, _: One) -> Self::Output { + -1 + } +} + +impl std::ops::Neg for One { + type Output = i32; + fn neg(self) -> Self::Output { + -1 } } @@ -94,4 +116,13 @@ fn main() { let _a = baz!(3, 4); let _b = baz!(3); + + let _ = { + unit!() - One //~ ERROR unnecessary parentheses around block return value + } + { + unit![] - One //~ ERROR unnecessary parentheses around block return value + } + { + // FIXME: false positive. This parenthesis is required. + unit! {} - One //~ ERROR unnecessary parentheses around block return value + }; } diff --git a/tests/ui/lint/lint-unnecessary-parens.rs b/tests/ui/lint/lint-unnecessary-parens.rs index 40cd61fcc2c0e..7cbaac8ae5403 100644 --- a/tests/ui/lint/lint-unnecessary-parens.rs +++ b/tests/ui/lint/lint-unnecessary-parens.rs @@ -46,6 +46,28 @@ pub fn parens_with_keyword(e: &[()]) -> i32 { macro_rules! baz { ($($foo:expr),+) => { ($($foo),*) + }; +} + +macro_rules! unit { + () => { + () + }; +} + +struct One; + +impl std::ops::Sub for () { + type Output = i32; + fn sub(self, _: One) -> Self::Output { + -1 + } +} + +impl std::ops::Neg for One { + type Output = i32; + fn neg(self) -> Self::Output { + -1 } } @@ -94,4 +116,13 @@ fn main() { let _a = baz!(3, 4); let _b = baz!(3); + + let _ = { + (unit!() - One) //~ ERROR unnecessary parentheses around block return value + } + { + (unit![] - One) //~ ERROR unnecessary parentheses around block return value + } + { + // FIXME: false positive. This parenthesis is required. + (unit! {} - One) //~ ERROR unnecessary parentheses around block return value + }; } diff --git a/tests/ui/lint/lint-unnecessary-parens.stderr b/tests/ui/lint/lint-unnecessary-parens.stderr index ba7a78b8da1a9..755dd5fc3094b 100644 --- a/tests/ui/lint/lint-unnecessary-parens.stderr +++ b/tests/ui/lint/lint-unnecessary-parens.stderr @@ -124,7 +124,7 @@ LL + return 1; | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:52:31 + --> $DIR/lint-unnecessary-parens.rs:74:31 | LL | pub const CONST_ITEM: usize = (10); | ^ ^ @@ -136,7 +136,7 @@ LL + pub const CONST_ITEM: usize = 10; | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:53:33 + --> $DIR/lint-unnecessary-parens.rs:75:33 | LL | pub static STATIC_ITEM: usize = (10); | ^ ^ @@ -148,7 +148,7 @@ LL + pub static STATIC_ITEM: usize = 10; | error: unnecessary parentheses around function argument - --> $DIR/lint-unnecessary-parens.rs:57:9 + --> $DIR/lint-unnecessary-parens.rs:79:9 | LL | bar((true)); | ^ ^ @@ -160,7 +160,7 @@ LL + bar(true); | error: unnecessary parentheses around `if` condition - --> $DIR/lint-unnecessary-parens.rs:59:8 + --> $DIR/lint-unnecessary-parens.rs:81:8 | LL | if (true) {} | ^ ^ @@ -172,7 +172,7 @@ LL + if true {} | error: unnecessary parentheses around `while` condition - --> $DIR/lint-unnecessary-parens.rs:60:11 + --> $DIR/lint-unnecessary-parens.rs:82:11 | LL | while (true) {} | ^ ^ @@ -184,7 +184,7 @@ LL + while true {} | error: unnecessary parentheses around `match` scrutinee expression - --> $DIR/lint-unnecessary-parens.rs:61:11 + --> $DIR/lint-unnecessary-parens.rs:83:11 | LL | match (true) { | ^ ^ @@ -196,7 +196,7 @@ LL + match true { | error: unnecessary parentheses around `let` scrutinee expression - --> $DIR/lint-unnecessary-parens.rs:64:16 + --> $DIR/lint-unnecessary-parens.rs:86:16 | LL | if let 1 = (1) {} | ^ ^ @@ -208,7 +208,7 @@ LL + if let 1 = 1 {} | error: unnecessary parentheses around `let` scrutinee expression - --> $DIR/lint-unnecessary-parens.rs:65:19 + --> $DIR/lint-unnecessary-parens.rs:87:19 | LL | while let 1 = (2) {} | ^ ^ @@ -220,7 +220,7 @@ LL + while let 1 = 2 {} | error: unnecessary parentheses around method argument - --> $DIR/lint-unnecessary-parens.rs:81:24 + --> $DIR/lint-unnecessary-parens.rs:103:24 | LL | X { y: false }.foo((true)); | ^ ^ @@ -232,7 +232,7 @@ LL + X { y: false }.foo(true); | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:83:18 + --> $DIR/lint-unnecessary-parens.rs:105:18 | LL | let mut _a = (0); | ^ ^ @@ -244,7 +244,7 @@ LL + let mut _a = 0; | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:84:10 + --> $DIR/lint-unnecessary-parens.rs:106:10 | LL | _a = (0); | ^ ^ @@ -256,7 +256,7 @@ LL + _a = 0; | error: unnecessary parentheses around assigned value - --> $DIR/lint-unnecessary-parens.rs:85:11 + --> $DIR/lint-unnecessary-parens.rs:107:11 | LL | _a += (1); | ^ ^ @@ -268,7 +268,7 @@ LL + _a += 1; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:87:8 + --> $DIR/lint-unnecessary-parens.rs:109:8 | LL | let(mut _a) = 3; | ^ ^ @@ -280,7 +280,7 @@ LL + let mut _a = 3; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:88:9 + --> $DIR/lint-unnecessary-parens.rs:110:9 | LL | let (mut _a) = 3; | ^ ^ @@ -292,7 +292,7 @@ LL + let mut _a = 3; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:89:8 + --> $DIR/lint-unnecessary-parens.rs:111:8 | LL | let( mut _a) = 3; | ^^ ^ @@ -304,7 +304,7 @@ LL + let mut _a = 3; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:91:8 + --> $DIR/lint-unnecessary-parens.rs:113:8 | LL | let(_a) = 3; | ^ ^ @@ -316,7 +316,7 @@ LL + let _a = 3; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:92:9 + --> $DIR/lint-unnecessary-parens.rs:114:9 | LL | let (_a) = 3; | ^ ^ @@ -328,7 +328,7 @@ LL + let _a = 3; | error: unnecessary parentheses around pattern - --> $DIR/lint-unnecessary-parens.rs:93:8 + --> $DIR/lint-unnecessary-parens.rs:115:8 | LL | let( _a) = 3; | ^^ ^ @@ -339,5 +339,41 @@ LL - let( _a) = 3; LL + let _a = 3; | -error: aborting due to 28 previous errors +error: unnecessary parentheses around block return value + --> $DIR/lint-unnecessary-parens.rs:121:9 + | +LL | (unit!() - One) + | ^ ^ + | +help: remove these parentheses + | +LL - (unit!() - One) +LL + unit!() - One + | + +error: unnecessary parentheses around block return value + --> $DIR/lint-unnecessary-parens.rs:123:9 + | +LL | (unit![] - One) + | ^ ^ + | +help: remove these parentheses + | +LL - (unit![] - One) +LL + unit![] - One + | + +error: unnecessary parentheses around block return value + --> $DIR/lint-unnecessary-parens.rs:126:9 + | +LL | (unit! {} - One) + | ^ ^ + | +help: remove these parentheses + | +LL - (unit! {} - One) +LL + unit! {} - One + | + +error: aborting due to 31 previous errors diff --git a/tests/ui/lint/reference_casting.rs b/tests/ui/lint/reference_casting.rs index d6897ab7b141a..87fa42f94775e 100644 --- a/tests/ui/lint/reference_casting.rs +++ b/tests/ui/lint/reference_casting.rs @@ -247,6 +247,27 @@ unsafe fn bigger_layout() { unsafe fn from_ref(this: &i32) -> &i64 { &*(this as *const i32 as *const i64) } + + // https://github.com/rust-lang/rust/issues/124685 + unsafe fn slice_index(array: &mut [u8], offset: usize) { + let a1 = &mut array[offset]; + let a2 = a1 as *mut u8; + let a3 = a2 as *mut u64; + unsafe { *a3 = 3 }; + } + + unsafe fn field_access(v: &mut Vec3) { + let r = &mut v.0; + let ptr = r as *mut i32 as *mut Vec3; + unsafe { *ptr = Vec3(0, 0, 0) } + } + + unsafe fn deref(v: &mut Vec3) { + let r = &mut v.0; + let r = &mut *r; + let ptr = &mut *(r as *mut i32 as *mut Vec3); + unsafe { *ptr = Vec3(0, 0, 0) } + } } const RAW_PTR: *mut u8 = 1 as *mut u8; diff --git a/tests/crashes/97006.rs b/tests/ui/macros/genercs-in-path-with-prettry-hir.rs similarity index 83% rename from tests/crashes/97006.rs rename to tests/ui/macros/genercs-in-path-with-prettry-hir.rs index c8dfa52ebee07..84370fcebbcbc 100644 --- a/tests/crashes/97006.rs +++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.rs @@ -1,7 +1,6 @@ -//@ known-bug: #97006 //@ compile-flags: -Zunpretty=hir -#![allow(unused)] +// issue#97006 macro_rules! m { ($attr_path: path) => { diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr b/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr new file mode 100644 index 0000000000000..8fcc7c6fbff06 --- /dev/null +++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr @@ -0,0 +1,8 @@ +error: unexpected generic arguments in path + --> $DIR/genercs-in-path-with-prettry-hir.rs:12:10 + | +LL | m!(inline); + | ^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout new file mode 100644 index 0000000000000..e9ee59abfae8d --- /dev/null +++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout @@ -0,0 +1,15 @@ +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; +//@ compile-flags: -Zunpretty=hir + +// issue#97006 + +macro_rules! m { ($attr_path: path) => { #[$attr_path] fn f() {} } } +#[ + +inline] +fn f() { } + +fn main() { } diff --git a/tests/ui/macros/macro-expand-within-generics-in-path.rs b/tests/ui/macros/macro-expand-within-generics-in-path.rs new file mode 100644 index 0000000000000..017d5152221bf --- /dev/null +++ b/tests/ui/macros/macro-expand-within-generics-in-path.rs @@ -0,0 +1,19 @@ +// issue#123911 +// issue#123912 + +macro_rules! m { + ($p: path) => { + #[$p] + struct S; + }; +} + +macro_rules! p { + () => {}; +} + +m!(generic); +//~^ ERROR: unexpected generic arguments in path +//~| ERROR: cannot find attribute `generic` in this scope + +fn main() {} diff --git a/tests/ui/macros/macro-expand-within-generics-in-path.stderr b/tests/ui/macros/macro-expand-within-generics-in-path.stderr new file mode 100644 index 0000000000000..72026c41050a2 --- /dev/null +++ b/tests/ui/macros/macro-expand-within-generics-in-path.stderr @@ -0,0 +1,14 @@ +error: unexpected generic arguments in path + --> $DIR/macro-expand-within-generics-in-path.rs:15:11 + | +LL | m!(generic); + | ^^^^^^ + +error: cannot find attribute `generic` in this scope + --> $DIR/macro-expand-within-generics-in-path.rs:15:4 + | +LL | m!(generic); + | ^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs index 492bd2450b1bf..6b215ba525deb 100644 --- a/tests/ui/macros/stringify.rs +++ b/tests/ui/macros/stringify.rs @@ -213,6 +213,21 @@ fn test_expr() { "match () { _ => ({ 1 }) - 1, }", "match () { _ => { 1 } - 1 }", ); + c2_match_arm!( + [ m!() - 1 ], + "match () { _ => m!() - 1, }", + "match () { _ => m!() - 1 }", + ); + c2_match_arm!( + [ m![] - 1 ], + "match () { _ => m![] - 1, }", + "match () { _ => m![] - 1 }", + ); + c2_match_arm!( + [ m! {} - 1 ], + "match () { _ => m! {} - 1, }", + "match () { _ => m! {} - 1 }", + ); // ExprKind::Closure c1!(expr, [ || {} ], "|| {}"); @@ -660,6 +675,11 @@ fn test_stmt() { "let (a, b): (u32, u32) = (1, 2);", "let (a, b): (u32, u32) = (1, 2)" ); + c2!(stmt, + [ let _ = f() else { return; } ], + "let _ = f() else { return; };", + "let _ = f() else { return; }", + ); macro_rules! c2_let_expr_minus_one { ([ $expr:expr ], $stmt_expected:expr, $tokens_expected:expr $(,)?) => { c2!(stmt, [ let _ = $expr - 1 ], $stmt_expected, $tokens_expected); @@ -670,6 +690,16 @@ fn test_stmt() { "let _ = match void {} - 1;", "let _ = match void {} - 1", ); + macro_rules! c2_let_expr_else_return { + ([ $expr:expr ], $stmt_expected:expr, $tokens_expected:expr $(,)?) => { + c2!(stmt, [ let _ = $expr else { return; } ], $stmt_expected, $tokens_expected); + }; + } + c2_let_expr_else_return!( + [ f() ], + "let _ = f() else { return; };", + "let _ = f() else { return; }", + ); // StmtKind::Item c1!(stmt, [ struct S; ], "struct S;"); @@ -720,6 +750,21 @@ fn test_stmt() { "(loop { break 1; }) - 1;", "loop { break 1; } - 1", ); + c2_minus_one!( + [ m!() ], + "m!() - 1;", + "m!() - 1" + ); + c2_minus_one!( + [ m![] ], + "m![] - 1;", + "m![] - 1" + ); + c2_minus_one!( + [ m! {} ], + "(m! {}) - 1;", + "m! {} - 1" + ); // StmtKind::Empty c1!(stmt, [ ; ], ";"); diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs index f1ac3e340e915..62e4f82a3ffbb 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs @@ -53,6 +53,12 @@ pub fn main() { if let Some(&Some(Some(&x))) = &Some(Some(&mut Some(0))) { let _: u32 = x; } + if let Some(&Some(&x)) = Some(&Some(&mut 0)) { + let _: u32 = x; + } + if let Some(&Some(x)) = &mut Some(Some(0)) { + let _: u32 = x; + } let &mut x = &&mut 0; let _: &u32 = x; diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs index ec091bb17467d..96b4ff77ddb4b 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs @@ -14,18 +14,20 @@ pub fn main() { let _: &mut u32 = x; //~^ ERROR: mismatched types } - if let Some(&Some(&_)) = Some(&Some(&mut 0)) { - //~^ ERROR: mismatched types - } if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { //~^ ERROR: mismatched types } if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) { //~^ ERROR: mismatched types } + if let Some(&mut Some(x)) = &Some(Some(0)) { + //~^ ERROR: mismatched types + } + if let Some(&mut Some(x)) = &Some(Some(0)) { + //~^ ERROR: mismatched types + } - - let &mut _= &&0; + let &mut _ = &&0; //~^ ERROR: mismatched types let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr index be71ee606c767..e06a645fc0d33 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr @@ -34,17 +34,6 @@ LL | let _: &mut u32 = x; error[E0308]: mismatched types --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:17:23 | -LL | if let Some(&Some(&_)) = Some(&Some(&mut 0)) { - | ^^ ------------------- this expression has type `Option<&Option<&mut {integer}>>` - | | - | types differ in mutability - | - = note: expected mutable reference `&mut {integer}` - found reference `&_` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:20:23 - | LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { | ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>` | | @@ -54,7 +43,7 @@ LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { found mutable reference `&mut _` error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:23:29 + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:20:29 | LL | if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) { | ^^^^^^ ------------------------- this expression has type `&Option>>` @@ -65,10 +54,32 @@ LL | if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) { found mutable reference `&mut _` error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:28:9 + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:23:17 + | +LL | if let Some(&mut Some(x)) = &Some(Some(0)) { + | ^^^^^^^^^^^^ -------------- this expression has type `&Option>` + | | + | expected `Option<{integer}>`, found `&mut _` + | + = note: expected enum `Option<{integer}>` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:26:17 + | +LL | if let Some(&mut Some(x)) = &Some(Some(0)) { + | ^^^^^^^^^^^^ -------------- this expression has type `&Option>` + | | + | expected `Option<{integer}>`, found `&mut _` + | + = note: expected enum `Option<{integer}>` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:30:9 | -LL | let &mut _= &&0; - | ^^^^^^ --- this expression has type `&&{integer}` +LL | let &mut _ = &&0; + | ^^^^^^ --- this expression has type `&&{integer}` | | | expected integer, found `&mut _` | @@ -76,7 +87,7 @@ LL | let &mut _= &&0; found mutable reference `&mut _` error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:31:9 + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:33:9 | LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; | ^^^^^^ ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` @@ -86,6 +97,6 @@ LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; = note: expected type `{integer}` found mutable reference `&mut _` -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs index 364554884073a..3cdf47c1dbfe1 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs @@ -8,4 +8,7 @@ pub fn main() { //~^ ERROR: cannot move out of a shared reference [E0507] let _: &u32 = x; } + + let &ref mut x = &0; + //~^ cannot borrow data in a `&` reference as mutable [E0596] } diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr index ccfb5c7a0c076..8b86fa65c4d8f 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr @@ -12,6 +12,13 @@ help: consider borrowing the pattern binding LL | if let Some(&Some(ref x)) = Some(&Some(&mut 0)) { | +++ -error: aborting due to 1 previous error +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/ref_pat_eat_one_layer_2024_fail2.rs:12:10 + | +LL | let &ref mut x = &0; + | ^^^^^^^^^ cannot borrow as mutable + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0507`. +Some errors have detailed explanations: E0507, E0596. +For more information about an error, try `rustc --explain E0507`. diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.fixed b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.fixed new file mode 100644 index 0000000000000..bc7a58a382d60 --- /dev/null +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.fixed @@ -0,0 +1,30 @@ +//@ edition: 2024 +//@ compile-flags: -Zunstable-options +//@ run-rustfix +#![allow(incomplete_features)] +#![feature(ref_pat_eat_one_layer_2024)] + +pub fn main() { + if let Some(&mut Some(ref mut x)) = &mut Some(Some(0)) { + //~^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut u8 = x; + } + + if let &mut Some(Some(ref mut x)) = &mut Some(Some(0)) { + //~^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut u8 = x; + } + + macro_rules! pat { + ($var:ident) => { ref mut $var }; + } + let &mut pat!(x) = &mut 0; + //~^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut u8 = x; + + let &mut (ref mut a, ref mut b) = &mut (true, false); + //~^ ERROR: cannot borrow as mutable inside an `&` pattern + //~| ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut bool = a; + let _: &mut bool = b; +} diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs new file mode 100644 index 0000000000000..c6d72b0a9d777 --- /dev/null +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs @@ -0,0 +1,30 @@ +//@ edition: 2024 +//@ compile-flags: -Zunstable-options +//@ run-rustfix +#![allow(incomplete_features)] +#![feature(ref_pat_eat_one_layer_2024)] + +pub fn main() { + if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { + //~^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut u8 = x; + } + + if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { + //~^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut u8 = x; + } + + macro_rules! pat { + ($var:ident) => { ref mut $var }; + } + let &pat!(x) = &mut 0; + //~^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut u8 = x; + + let &(ref mut a, ref mut b) = &mut (true, false); + //~^ ERROR: cannot borrow as mutable inside an `&` pattern + //~| ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut bool = a; + let _: &mut bool = b; +} diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.stderr new file mode 100644 index 0000000000000..964e9f36596bd --- /dev/null +++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.stderr @@ -0,0 +1,43 @@ +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:8:31 + | +LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:13:31 + | +LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:21:15 + | +LL | let &pat!(x) = &mut 0; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:25:19 + | +LL | let &(ref mut a, ref mut b) = &mut (true, false); + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:25:30 + | +LL | let &(ref mut a, ref mut b) = &mut (true, false); + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/match/ref_pat_everywhere-mutability-mismatch.rs b/tests/ui/match/ref_pat_everywhere-fail.rs similarity index 63% rename from tests/ui/match/ref_pat_everywhere-mutability-mismatch.rs rename to tests/ui/match/ref_pat_everywhere-fail.rs index 9dd7a7893ec71..d1b1c04730d34 100644 --- a/tests/ui/match/ref_pat_everywhere-mutability-mismatch.rs +++ b/tests/ui/match/ref_pat_everywhere-fail.rs @@ -5,11 +5,7 @@ pub fn main() { //~^ ERROR: mismatched types [E0308] let _: u32 = x; } - if let &Some(x) = &mut Some(0) { - //~^ ERROR: mismatched types [E0308] - let _: u32 = x; - } - if let Some(&x) = &mut Some(0) { + if let Some(&mut x) = Some(&0) { //~^ ERROR: mismatched types [E0308] let _: u32 = x; } diff --git a/tests/ui/match/ref_pat_everywhere-fail.stderr b/tests/ui/match/ref_pat_everywhere-fail.stderr new file mode 100644 index 0000000000000..25a01129f4a9d --- /dev/null +++ b/tests/ui/match/ref_pat_everywhere-fail.stderr @@ -0,0 +1,38 @@ +error[E0308]: mismatched types + --> $DIR/ref_pat_everywhere-fail.rs:4:17 + | +LL | if let Some(&x) = Some(0) { + | ^^ ------- this expression has type `Option<{integer}>` + | | + | expected integer, found `&_` + | + = note: expected type `{integer}` + found reference `&_` +help: consider removing `&` from the pattern + | +LL | if let Some(x) = Some(0) { + | ~ + +error[E0308]: mismatched types + --> $DIR/ref_pat_everywhere-fail.rs:8:17 + | +LL | if let Some(&mut x) = Some(&0) { + | ^^^^^^ -------- this expression has type `Option<&{integer}>` + | | + | types differ in mutability + | + = note: expected reference `&{integer}` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut x` + --> $DIR/ref_pat_everywhere-fail.rs:8:17 + | +LL | if let Some(&mut x) = Some(&0) { + | ^^^^^^ +help: consider removing `&mut` from the pattern + | +LL | if let Some(x) = Some(&0) { + | ~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/match/ref_pat_everywhere-mutability-mismatch.stderr b/tests/ui/match/ref_pat_everywhere-mutability-mismatch.stderr deleted file mode 100644 index d512ea5f957da..0000000000000 --- a/tests/ui/match/ref_pat_everywhere-mutability-mismatch.stderr +++ /dev/null @@ -1,44 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/ref_pat_everywhere-mutability-mismatch.rs:4:17 - | -LL | if let Some(&x) = Some(0) { - | ^^ ------- this expression has type `Option<{integer}>` - | | - | expected integer, found `&_` - | - = note: expected type `{integer}` - found reference `&_` -help: consider removing `&` from the pattern - | -LL | if let Some(x) = Some(0) { - | ~ - -error[E0308]: mismatched types - --> $DIR/ref_pat_everywhere-mutability-mismatch.rs:8:12 - | -LL | if let &Some(x) = &mut Some(0) { - | ^^^^^^^^ ------------ this expression has type `&mut Option<{integer}>` - | | - | types differ in mutability - | - = note: expected mutable reference `&mut Option<{integer}>` - found reference `&_` - -error[E0308]: mismatched types - --> $DIR/ref_pat_everywhere-mutability-mismatch.rs:12:17 - | -LL | if let Some(&x) = &mut Some(0) { - | ^^ ------------ this expression has type `&mut Option<{integer}>` - | | - | expected integer, found `&_` - | - = note: expected type `{integer}` - found reference `&_` -help: consider removing `&` from the pattern - | -LL | if let Some(x) = &mut Some(0) { - | ~ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/match/ref_pat_everywhere.rs b/tests/ui/match/ref_pat_everywhere.rs index b3daca484092b..9a79c548475f6 100644 --- a/tests/ui/match/ref_pat_everywhere.rs +++ b/tests/ui/match/ref_pat_everywhere.rs @@ -15,4 +15,10 @@ pub fn main() { if let Some(Some(&x)) = &Some(&mut Some(0)) { let _: u32 = x; } + if let &Some(x) = &mut Some(0) { + let _: u32 = x; + } + if let Some(&x) = &mut Some(0) { + let _: u32 = x; + } } diff --git a/tests/ui/meta/meta-expected-error-wrong-rev.a.stderr b/tests/ui/meta/meta-expected-error-wrong-rev.a.stderr index 4221dd04cfaac..a489040f32df6 100644 --- a/tests/ui/meta/meta-expected-error-wrong-rev.a.stderr +++ b/tests/ui/meta/meta-expected-error-wrong-rev.a.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/meta-expected-error-wrong-rev.rs:13:18 + --> $DIR/meta-expected-error-wrong-rev.rs:14:18 | LL | let x: u32 = 22_usize; | --- ^^^^^^^^ expected `u32`, found `usize` diff --git a/tests/ui/meta/meta-expected-error-wrong-rev.rs b/tests/ui/meta/meta-expected-error-wrong-rev.rs index de27629948290..1c3a3fc492329 100644 --- a/tests/ui/meta/meta-expected-error-wrong-rev.rs +++ b/tests/ui/meta/meta-expected-error-wrong-rev.rs @@ -1,6 +1,7 @@ //@ ignore-compare-mode-polonius //@ revisions: a +//@ unused-revision-names: b //@ should-fail // This is a "meta-test" of the compilertest framework itself. In diff --git a/tests/ui/methods/method-lookup-order.rs b/tests/ui/methods/method-lookup-order.rs index f794e5a72415e..ad56da966867d 100644 --- a/tests/ui/methods/method-lookup-order.rs +++ b/tests/ui/methods/method-lookup-order.rs @@ -17,6 +17,7 @@ // {mutbar_for_foo, valbar_for_etmut_foo} (which are lower precedent than the inherent `&mut self` method on `Foo`; e.g. b10101 *is* included. //@ revisions: b00001 b00010 b00011 b00100 b00101 b00110 b00111 b01000 b01001 b01100 b01101 b10000 b10001 b10010 b10011 b10101 b10111 b11000 b11001 b11101 +//@ unused-revision-names: b01010 b01011 b01110 b01111 b10100 b10110 b11010 b11011 b11100 b11110 b11111 //@ compile-flags: --check-cfg=cfg(inherent_mut,bar_for_foo,mutbar_for_foo) //@ compile-flags: --check-cfg=cfg(valbar_for_et_foo,valbar_for_etmut_foo) diff --git a/tests/ui/mismatched_types/non_zero_assigned_something.rs b/tests/ui/mismatched_types/non_zero_assigned_something.rs index d2adbe01c1828..e94d5249d6a84 100644 --- a/tests/ui/mismatched_types/non_zero_assigned_something.rs +++ b/tests/ui/mismatched_types/non_zero_assigned_something.rs @@ -1,9 +1,9 @@ fn main() { - let _: std::num::NonZeroU64 = 1; + let _: std::num::NonZero = 1; //~^ ERROR mismatched types - //~| HELP consider calling `NonZeroU64::new` + //~| HELP consider calling `NonZero::new` - let _: Option = 1; + let _: Option> = 1; //~^ ERROR mismatched types - //~| HELP consider calling `NonZeroU64::new` + //~| HELP consider calling `NonZero::new` } diff --git a/tests/ui/mismatched_types/non_zero_assigned_something.stderr b/tests/ui/mismatched_types/non_zero_assigned_something.stderr index f8e86905ab9bb..aa015bd2efcc9 100644 --- a/tests/ui/mismatched_types/non_zero_assigned_something.stderr +++ b/tests/ui/mismatched_types/non_zero_assigned_something.stderr @@ -1,32 +1,32 @@ error[E0308]: mismatched types - --> $DIR/non_zero_assigned_something.rs:2:35 + --> $DIR/non_zero_assigned_something.rs:2:37 | -LL | let _: std::num::NonZeroU64 = 1; - | -------------------- ^ expected `NonZero`, found integer +LL | let _: std::num::NonZero = 1; + | ---------------------- ^ expected `NonZero`, found integer | | | expected due to this | = note: expected struct `NonZero` found type `{integer}` -help: consider calling `NonZeroU64::new` +help: consider calling `NonZero::new` | -LL | let _: std::num::NonZeroU64 = NonZeroU64::new(1).unwrap(); - | ++++++++++++++++ ++++++++++ +LL | let _: std::num::NonZero = NonZero::new(1).unwrap(); + | +++++++++++++ ++++++++++ error[E0308]: mismatched types - --> $DIR/non_zero_assigned_something.rs:6:43 + --> $DIR/non_zero_assigned_something.rs:6:45 | -LL | let _: Option = 1; - | ---------------------------- ^ expected `Option>`, found integer +LL | let _: Option> = 1; + | ------------------------------ ^ expected `Option>`, found integer | | | expected due to this | = note: expected enum `Option>` found type `{integer}` -help: consider calling `NonZeroU64::new` +help: consider calling `NonZero::new` | -LL | let _: Option = NonZeroU64::new(1); - | ++++++++++++++++ + +LL | let _: Option> = NonZero::new(1); + | +++++++++++++ + error: aborting due to 2 previous errors diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.rs b/tests/ui/parser/attribute/attr-bad-meta-4.rs index cedbd1d6686bc..2a69ae5ac0639 100644 --- a/tests/ui/parser/attribute/attr-bad-meta-4.rs +++ b/tests/ui/parser/attribute/attr-bad-meta-4.rs @@ -1,12 +1,17 @@ macro_rules! mac { ($attr_item: meta) => { #[cfg($attr_item)] - //~^ ERROR expected unsuffixed literal or identifier, found `an(arbitrary token stream)` - //~| ERROR expected unsuffixed literal or identifier, found `an(arbitrary token stream)` + //~^ ERROR expected unsuffixed literal, found `an(arbitrary token stream)` + //~| ERROR expected unsuffixed literal, found `an(arbitrary token stream)` struct S; } } mac!(an(arbitrary token stream)); +#[cfg(feature = -1)] +//~^ ERROR expected unsuffixed literal, found `-` +//~| ERROR expected unsuffixed literal, found `-` +fn handler() {} + fn main() {} diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.stderr b/tests/ui/parser/attribute/attr-bad-meta-4.stderr index a543bcb692e60..192be28db3fb8 100644 --- a/tests/ui/parser/attribute/attr-bad-meta-4.stderr +++ b/tests/ui/parser/attribute/attr-bad-meta-4.stderr @@ -1,4 +1,10 @@ -error: expected unsuffixed literal or identifier, found `an(arbitrary token stream)` +error: expected unsuffixed literal, found `-` + --> $DIR/attr-bad-meta-4.rs:12:17 + | +LL | #[cfg(feature = -1)] + | ^ + +error: expected unsuffixed literal, found `an(arbitrary token stream)` --> $DIR/attr-bad-meta-4.rs:3:15 | LL | #[cfg($attr_item)] @@ -9,7 +15,7 @@ LL | mac!(an(arbitrary token stream)); | = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected unsuffixed literal or identifier, found `an(arbitrary token stream)` +error: expected unsuffixed literal, found `an(arbitrary token stream)` --> $DIR/attr-bad-meta-4.rs:3:15 | LL | #[cfg($attr_item)] @@ -21,5 +27,13 @@ LL | mac!(an(arbitrary token stream)); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors +error: expected unsuffixed literal, found `-` + --> $DIR/attr-bad-meta-4.rs:12:17 + | +LL | #[cfg(feature = -1)] + | ^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.fixed b/tests/ui/parser/attribute/attr-unquoted-ident.fixed deleted file mode 100644 index bc861ef69fb7c..0000000000000 --- a/tests/ui/parser/attribute/attr-unquoted-ident.fixed +++ /dev/null @@ -1,17 +0,0 @@ -//@ compile-flags: -Zdeduplicate-diagnostics=yes -//@ run-rustfix - -#![allow(unexpected_cfgs)] - -fn main() { - #[cfg(key="foo")] - //~^ ERROR expected unsuffixed literal, found `foo` - //~| HELP surround the identifier with quotation marks to parse it as a string - println!(); - #[cfg(key="bar")] - println!(); - #[cfg(key="foo bar baz")] - //~^ ERROR expected unsuffixed literal, found `foo` - //~| HELP surround the identifier with quotation marks to parse it as a string - println!(); -} diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.rs b/tests/ui/parser/attribute/attr-unquoted-ident.rs index 8bdb8605ebb4f..5b15b8d69fcf8 100644 --- a/tests/ui/parser/attribute/attr-unquoted-ident.rs +++ b/tests/ui/parser/attribute/attr-unquoted-ident.rs @@ -1,17 +1,25 @@ //@ compile-flags: -Zdeduplicate-diagnostics=yes -//@ run-rustfix #![allow(unexpected_cfgs)] fn main() { #[cfg(key=foo)] //~^ ERROR expected unsuffixed literal, found `foo` - //~| HELP surround the identifier with quotation marks to parse it as a string + //~| HELP surround the identifier with quotation marks to make it into a string literal println!(); #[cfg(key="bar")] println!(); #[cfg(key=foo bar baz)] //~^ ERROR expected unsuffixed literal, found `foo` - //~| HELP surround the identifier with quotation marks to parse it as a string + //~| HELP surround the identifier with quotation marks to make it into a string literal println!(); } + +// Don't suggest surrounding `$name` or `nickname` with quotes: + +macro_rules! make { + ($name:ident) => { #[doc(alias = $name)] pub struct S; } + //~^ ERROR expected unsuffixed literal, found `nickname` +} + +make!(nickname); //~ NOTE in this expansion diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.stderr b/tests/ui/parser/attribute/attr-unquoted-ident.stderr index 99484a51110f1..e0f99459c44e7 100644 --- a/tests/ui/parser/attribute/attr-unquoted-ident.stderr +++ b/tests/ui/parser/attribute/attr-unquoted-ident.stderr @@ -1,24 +1,35 @@ error: expected unsuffixed literal, found `foo` - --> $DIR/attr-unquoted-ident.rs:7:15 + --> $DIR/attr-unquoted-ident.rs:6:15 | LL | #[cfg(key=foo)] | ^^^ | -help: surround the identifier with quotation marks to parse it as a string +help: surround the identifier with quotation marks to make it into a string literal | LL | #[cfg(key="foo")] | + + error: expected unsuffixed literal, found `foo` - --> $DIR/attr-unquoted-ident.rs:13:15 + --> $DIR/attr-unquoted-ident.rs:12:15 | LL | #[cfg(key=foo bar baz)] | ^^^ | -help: surround the identifier with quotation marks to parse it as a string +help: surround the identifier with quotation marks to make it into a string literal | LL | #[cfg(key="foo bar baz")] | + + -error: aborting due to 2 previous errors +error: expected unsuffixed literal, found `nickname` + --> $DIR/attr-unquoted-ident.rs:21:38 + | +LL | ($name:ident) => { #[doc(alias = $name)] pub struct S; } + | ^^^^^ +... +LL | make!(nickname); + | --------------- in this macro invocation + | + = note: this error originates in the macro `make` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors diff --git a/tests/ui/parser/else-no-if.rs b/tests/ui/parser/else-no-if.rs index f0b40ecde6660..ad5262cd2cc93 100644 --- a/tests/ui/parser/else-no-if.rs +++ b/tests/ui/parser/else-no-if.rs @@ -1,3 +1,7 @@ +macro_rules! falsy { + () => { false }; +} + fn foo() { if true { } else false { @@ -25,6 +29,32 @@ fn foo4() { {} } +fn foo5() { + if true { + } else falsy!() { + //~^ ERROR expected `{`, found `falsy` + } +} + +fn foo6() { + if true { + } else falsy!(); + //~^ ERROR expected `{`, found `falsy` +} + +fn foo7() { + if true { + } else falsy! {} { + //~^ ERROR expected `{`, found `falsy` + } +} + +fn foo8() { + if true { + } else falsy! {}; + //~^ ERROR expected `{`, found `falsy` +} + fn falsy() -> bool { false } diff --git a/tests/ui/parser/else-no-if.stderr b/tests/ui/parser/else-no-if.stderr index b9c1a75276c1f..2e3e8f6b50e95 100644 --- a/tests/ui/parser/else-no-if.stderr +++ b/tests/ui/parser/else-no-if.stderr @@ -1,5 +1,5 @@ error: expected `{`, found keyword `false` - --> $DIR/else-no-if.rs:3:12 + --> $DIR/else-no-if.rs:7:12 | LL | } else false { | ---- ^^^^^ @@ -12,7 +12,7 @@ LL | } else if false { | ++ error: expected `{`, found `falsy` - --> $DIR/else-no-if.rs:10:12 + --> $DIR/else-no-if.rs:14:12 | LL | } else falsy() { | ---- ^^^^^ @@ -25,7 +25,7 @@ LL | } else if falsy() { | ++ error: expected `{`, found `falsy` - --> $DIR/else-no-if.rs:17:12 + --> $DIR/else-no-if.rs:21:12 | LL | } else falsy(); | ^^^^^ expected `{` @@ -36,7 +36,7 @@ LL | } else { falsy() }; | + + error: expected `{`, found keyword `loop` - --> $DIR/else-no-if.rs:23:12 + --> $DIR/else-no-if.rs:27:12 | LL | } else loop{} | ^^^^ expected `{` @@ -46,5 +46,51 @@ help: try placing this code inside a block LL | } else { loop{} } | + + -error: aborting due to 4 previous errors +error: expected `{`, found `falsy` + --> $DIR/else-no-if.rs:34:12 + | +LL | } else falsy!() { + | ---- ^^^^^ + | | + | expected an `if` or a block after this `else` + | +help: add an `if` if this is the condition of a chained `else if` statement + | +LL | } else if falsy!() { + | ++ + +error: expected `{`, found `falsy` + --> $DIR/else-no-if.rs:41:12 + | +LL | } else falsy!(); + | ^^^^^ expected `{` + | +help: try placing this code inside a block + | +LL | } else { falsy!() }; + | + + + +error: expected `{`, found `falsy` + --> $DIR/else-no-if.rs:47:12 + | +LL | } else falsy! {} { + | ^^^^^ expected `{` + | +help: try placing this code inside a block + | +LL | } else { falsy! {} } { + | + + + +error: expected `{`, found `falsy` + --> $DIR/else-no-if.rs:54:12 + | +LL | } else falsy! {}; + | ^^^^^ expected `{` + | +help: try placing this code inside a block + | +LL | } else { falsy! {} }; + | + + + +error: aborting due to 8 previous errors diff --git a/tests/ui/parser/macro/statement-boundaries.rs b/tests/ui/parser/macro/statement-boundaries.rs new file mode 100644 index 0000000000000..67a6aa30f0c5e --- /dev/null +++ b/tests/ui/parser/macro/statement-boundaries.rs @@ -0,0 +1,104 @@ +//@ run-pass +//@ edition:2021 + +// This is a test of several uses of rustc_ast::util::classify::expr_requires_semi_to_be_stmt +// by the Rust parser, which relates to the insertion of statement boundaries +// after certain kinds of expressions if they appear at the head of a statement. + +#![allow(unused_braces, unused_unsafe)] + +macro_rules! unit { + () => { + { () } + }; +} + +#[derive(Copy, Clone)] +struct X; + +fn main() { + let x = X; + + // There is a statement boundary before `|x| x`, so it's a closure. + let _: fn(X) -> X = { if true {} |x| x }; + let _: fn(X) -> X = { if true {} else {} |x| x }; + let _: fn(X) -> X = { match () { () => {} } |x| x }; + let _: fn(X) -> X = { { () } |x| x }; + let _: fn(X) -> X = { unsafe {} |x| x }; + let _: fn(X) -> X = { while false {} |x| x }; + let _: fn(X) -> X = { loop { break; } |x| x }; + let _: fn(X) -> X = { for _ in 0..0 {} |x| x }; + let _: fn(X) -> X = { const {} |x| x }; + let _: fn(X) -> X = { unit! {} |x| x }; + + // No statement boundary, so `|x| x` is 2× BitOr operation. + () = { "" |x| x }; + () = { ("") |x| x }; + () = { [""] |x| x }; + () = { unit!() |x| x }; + () = { unit![] |x| x }; + + // All the same cases, but as a match arm. + () = match x { + // Statement boundary before `| X`, which becomes a new arm with leading vert. + X if false => if true {} | X if false => {} + X if false => if true {} else {} | X if false => {} + X if false => match () { () => {} } | X if false => {} + X if false => { () } | X if false => {} + X if false => unsafe {} | X if false => {} + X if false => while false {} | X if false => {} + X if false => loop { break; } | X if false => {} + X if false => for _ in 0..0 {} | X if false => {} + X if false => const {} | X if false => {} + + // No statement boundary, so `| X` is BitOr. + X if false => "" | X, + X if false => ("") | X, + X if false => [""] | X, + X if false => unit! {} | X, // !! inconsistent with braced mac call in statement position + X if false => unit!() | X, + X if false => unit![] | X, + + X => {} + }; + + // Test how the statement boundary logic interacts with macro metavariables / + // "invisible delimiters". + macro_rules! assert_statement_boundary { + ($expr:expr) => { + let _: fn(X) -> X = { $expr |x| x }; + + () = match X { + X if false => $expr | X if false => {} + X => {} + }; + }; + } + macro_rules! assert_no_statement_boundary { + ($expr:expr) => { + () = { $expr |x| x }; + + () = match x { + X if false => $expr | X, + X => {} + }; + }; + } + assert_statement_boundary!(if true {}); + assert_no_statement_boundary!(""); +} + +impl std::ops::BitOr for () { + type Output = (); + fn bitor(self, _: X) {} +} + +impl std::ops::BitOr for &str { + type Output = (); + fn bitor(self, _: X) {} +} + +impl std::ops::BitOr for [T; N] { + type Output = (); + fn bitor(self, _: X) {} +} diff --git a/tests/ui/parser/recover/turbofish-arg-with-stray-colon.rs b/tests/ui/parser/recover/turbofish-arg-with-stray-colon.rs new file mode 100644 index 0000000000000..32125211a910f --- /dev/null +++ b/tests/ui/parser/recover/turbofish-arg-with-stray-colon.rs @@ -0,0 +1,6 @@ +fn foo() { + let x = Tr; + //~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `,` +} + +fn main() {} diff --git a/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr b/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr new file mode 100644 index 0000000000000..551b2e3ff09b0 --- /dev/null +++ b/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr @@ -0,0 +1,14 @@ +error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `,` + --> $DIR/turbofish-arg-with-stray-colon.rs:2:17 + | +LL | let x = Tr; + | ^ expected one of 8 possible tokens + | + = note: type ascription syntax has been removed, see issue #101728 +help: maybe write a path separator here + | +LL | let x = Tr; + | ~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/pattern/auxiliary/match_ergonomics_2024_macros.rs b/tests/ui/pattern/auxiliary/match_ergonomics_2024_macros.rs new file mode 100644 index 0000000000000..0b70e4404abce --- /dev/null +++ b/tests/ui/pattern/auxiliary/match_ergonomics_2024_macros.rs @@ -0,0 +1,12 @@ +//@ edition: 2024 +//@ compile-flags: -Z unstable-options + +// This contains a binding in edition 2024, so if matched with a reference binding mode it will end +// up with a `mut ref mut` binding mode. We use this to test the migration lint on patterns with +// mixed editions. +#[macro_export] +macro_rules! mixed_edition_pat { + ($foo:ident) => { + Some(mut $foo) + }; +} diff --git a/tests/ui/pattern/match_ergonomics_2024.fixed b/tests/ui/pattern/match_ergonomics_2024.fixed new file mode 100644 index 0000000000000..d8dbcb217c040 --- /dev/null +++ b/tests/ui/pattern/match_ergonomics_2024.fixed @@ -0,0 +1,57 @@ +//@ edition: 2021 +//@ run-rustfix +//@ rustfix-only-machine-applicable +//@ aux-build:match_ergonomics_2024_macros.rs +#![feature(mut_preserve_binding_mode_2024, ref_pat_eat_one_layer_2024)] +#![allow(incomplete_features, unused)] +#![deny(rust_2024_incompatible_pat)] + +extern crate match_ergonomics_2024_macros; + +struct Foo(u8); + +fn main() { + let &Foo(mut a) = &Foo(0); + //~^ ERROR: the semantics of this pattern will change in edition 2024 + a = 42; + + let &mut Foo(mut a) = &mut Foo(0); + //~^ ERROR: the semantics of this pattern will change in edition 2024 + a = 42; + + if let &&&&&Some(&_) = &&&&&Some(&0u8) {} + //~^ ERROR: the semantics of this pattern will change in edition 2024 + + if let &&&&&Some(&mut _) = &&&&&Some(&mut 0u8) {} + //~^ ERROR: the semantics of this pattern will change in edition 2024 + + if let &&&&&mut Some(&_) = &&&&&mut Some(&0u8) {} + //~^ ERROR: the semantics of this pattern will change in edition 2024 + + if let &mut Some(&mut Some(&mut Some(_))) = &mut Some(&mut Some(&mut Some(0u8))) {} + //~^ ERROR: the semantics of this pattern will change in edition 2024 + + if let &mut Some(&mut Some(&mut Some(ref mut _a))) = &mut Some(&mut Some(&mut Some(0u8))) {} + //~^ ERROR: the semantics of this pattern will change in edition 2024 + + struct Struct { + a: u32, + b: u32, + c: u32, + } + let s = Struct { a: 0, b: 0, c: 0 }; + let &Struct { ref a, mut b, ref c } = &s; + //~^ ERROR: the semantics of this pattern will change in edition 2024 + + #[warn(rust_2024_incompatible_pat)] + match &(Some(0), Some(0)) { + // The two patterns are the same syntactically, but because they're defined in different + // editions they don't mean the same thing. + (Some(mut _x), match_ergonomics_2024_macros::mixed_edition_pat!(_y)) => { + //~^ WARN: the semantics of this pattern will change in edition 2024 + _x = 4; + _y = &7; + } + _ => {} + } +} diff --git a/tests/ui/pattern/match_ergonomics_2024.rs b/tests/ui/pattern/match_ergonomics_2024.rs new file mode 100644 index 0000000000000..38dc0c8bebb2f --- /dev/null +++ b/tests/ui/pattern/match_ergonomics_2024.rs @@ -0,0 +1,57 @@ +//@ edition: 2021 +//@ run-rustfix +//@ rustfix-only-machine-applicable +//@ aux-build:match_ergonomics_2024_macros.rs +#![feature(mut_preserve_binding_mode_2024, ref_pat_eat_one_layer_2024)] +#![allow(incomplete_features, unused)] +#![deny(rust_2024_incompatible_pat)] + +extern crate match_ergonomics_2024_macros; + +struct Foo(u8); + +fn main() { + let Foo(mut a) = &Foo(0); + //~^ ERROR: the semantics of this pattern will change in edition 2024 + a = 42; + + let Foo(mut a) = &mut Foo(0); + //~^ ERROR: the semantics of this pattern will change in edition 2024 + a = 42; + + if let Some(&_) = &&&&&Some(&0u8) {} + //~^ ERROR: the semantics of this pattern will change in edition 2024 + + if let Some(&mut _) = &&&&&Some(&mut 0u8) {} + //~^ ERROR: the semantics of this pattern will change in edition 2024 + + if let Some(&_) = &&&&&mut Some(&0u8) {} + //~^ ERROR: the semantics of this pattern will change in edition 2024 + + if let Some(&mut Some(Some(_))) = &mut Some(&mut Some(&mut Some(0u8))) {} + //~^ ERROR: the semantics of this pattern will change in edition 2024 + + if let Some(&mut Some(Some(_a))) = &mut Some(&mut Some(&mut Some(0u8))) {} + //~^ ERROR: the semantics of this pattern will change in edition 2024 + + struct Struct { + a: u32, + b: u32, + c: u32, + } + let s = Struct { a: 0, b: 0, c: 0 }; + let Struct { a, mut b, c } = &s; + //~^ ERROR: the semantics of this pattern will change in edition 2024 + + #[warn(rust_2024_incompatible_pat)] + match &(Some(0), Some(0)) { + // The two patterns are the same syntactically, but because they're defined in different + // editions they don't mean the same thing. + (Some(mut _x), match_ergonomics_2024_macros::mixed_edition_pat!(_y)) => { + //~^ WARN: the semantics of this pattern will change in edition 2024 + _x = 4; + _y = &7; + } + _ => {} + } +} diff --git a/tests/ui/pattern/match_ergonomics_2024.stderr b/tests/ui/pattern/match_ergonomics_2024.stderr new file mode 100644 index 0000000000000..11844434ad214 --- /dev/null +++ b/tests/ui/pattern/match_ergonomics_2024.stderr @@ -0,0 +1,97 @@ +error: the semantics of this pattern will change in edition 2024 + --> $DIR/match_ergonomics_2024.rs:14:9 + | +LL | let Foo(mut a) = &Foo(0); + | -^^^^^^^^^ + | | + | help: desugar the match ergonomics: `&` + | +note: the lint level is defined here + --> $DIR/match_ergonomics_2024.rs:7:9 + | +LL | #![deny(rust_2024_incompatible_pat)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the semantics of this pattern will change in edition 2024 + --> $DIR/match_ergonomics_2024.rs:18:9 + | +LL | let Foo(mut a) = &mut Foo(0); + | -^^^^^^^^^ + | | + | help: desugar the match ergonomics: `&mut` + +error: the semantics of this pattern will change in edition 2024 + --> $DIR/match_ergonomics_2024.rs:22:12 + | +LL | if let Some(&_) = &&&&&Some(&0u8) {} + | -^^^^^^^ + | | + | help: desugar the match ergonomics: `&&&&&` + +error: the semantics of this pattern will change in edition 2024 + --> $DIR/match_ergonomics_2024.rs:25:12 + | +LL | if let Some(&mut _) = &&&&&Some(&mut 0u8) {} + | -^^^^^^^^^^^ + | | + | help: desugar the match ergonomics: `&&&&&` + +error: the semantics of this pattern will change in edition 2024 + --> $DIR/match_ergonomics_2024.rs:28:12 + | +LL | if let Some(&_) = &&&&&mut Some(&0u8) {} + | -^^^^^^^ + | | + | help: desugar the match ergonomics: `&&&&&mut` + +error: the semantics of this pattern will change in edition 2024 + --> $DIR/match_ergonomics_2024.rs:31:12 + | +LL | if let Some(&mut Some(Some(_))) = &mut Some(&mut Some(&mut Some(0u8))) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: desugar the match ergonomics + | +LL | if let &mut Some(&mut Some(&mut Some(_))) = &mut Some(&mut Some(&mut Some(0u8))) {} + | ++++ ++++ + +error: the semantics of this pattern will change in edition 2024 + --> $DIR/match_ergonomics_2024.rs:34:12 + | +LL | if let Some(&mut Some(Some(_a))) = &mut Some(&mut Some(&mut Some(0u8))) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: desugar the match ergonomics + | +LL | if let &mut Some(&mut Some(&mut Some(ref mut _a))) = &mut Some(&mut Some(&mut Some(0u8))) {} + | ++++ ++++ +++++++ + +error: the semantics of this pattern will change in edition 2024 + --> $DIR/match_ergonomics_2024.rs:43:9 + | +LL | let Struct { a, mut b, c } = &s; + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: desugar the match ergonomics + | +LL | let &Struct { ref a, mut b, ref c } = &s; + | + +++ +++ + +warning: the semantics of this pattern will change in edition 2024 + --> $DIR/match_ergonomics_2024.rs:50:9 + | +LL | (Some(mut _x), match_ergonomics_2024_macros::mixed_edition_pat!(_y)) => { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/match_ergonomics_2024.rs:46:12 + | +LL | #[warn(rust_2024_incompatible_pat)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: desugar the match ergonomics + | +LL | &(Some(mut _x), match_ergonomics_2024_macros::mixed_edition_pat!(ref _y)) => { + | + +++ + +error: aborting due to 8 previous errors; 1 warning emitted + diff --git a/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.rs b/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.rs deleted file mode 100644 index 249f251d2cd2e..0000000000000 --- a/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ edition: 2021 -#![feature(mut_preserve_binding_mode_2024)] -#![allow(incomplete_features, unused)] -#![forbid(dereferencing_mut_binding)] - -struct Foo(u8); - -fn main() { - let Foo(mut a) = &Foo(0); - //~^ ERROR: dereferencing `mut` binding - a = 42; - - let Foo(mut a) = &mut Foo(0); - //~^ ERROR: dereferencing `mut` binding - a = 42; -} diff --git a/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.stderr b/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.stderr deleted file mode 100644 index e8d11acd83e50..0000000000000 --- a/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error: dereferencing `mut` binding - --> $DIR/mut_preserve_binding_mode_2024_lint.rs:9:13 - | -LL | let Foo(mut a) = &Foo(0); - | ^^^^^ `mut` dereferences the type of this binding - | -help: this will change in edition 2024 - --> $DIR/mut_preserve_binding_mode_2024_lint.rs:9:13 - | -LL | let Foo(mut a) = &Foo(0); - | ^^^^^ -note: the lint level is defined here - --> $DIR/mut_preserve_binding_mode_2024_lint.rs:4:11 - | -LL | #![forbid(dereferencing_mut_binding)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: dereferencing `mut` binding - --> $DIR/mut_preserve_binding_mode_2024_lint.rs:13:13 - | -LL | let Foo(mut a) = &mut Foo(0); - | ^^^^^ `mut` dereferences the type of this binding - | -help: this will change in edition 2024 - --> $DIR/mut_preserve_binding_mode_2024_lint.rs:13:13 - | -LL | let Foo(mut a) = &mut Foo(0); - | ^^^^^ - -error: aborting due to 2 previous errors - diff --git a/tests/ui/resolve/issue-50599.stderr b/tests/ui/resolve/issue-50599.stderr index 25e98b4746b79..e5eacd741fbe2 100644 --- a/tests/ui/resolve/issue-50599.stderr +++ b/tests/ui/resolve/issue-50599.stderr @@ -6,6 +6,10 @@ LL | const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize; | help: consider importing one of these items | +LL + use std::f128::consts::LOG10_2; + | +LL + use std::f16::consts::LOG10_2; + | LL + use std::f32::consts::LOG10_2; | LL + use std::f64::consts::LOG10_2; diff --git a/tests/ui/resolve/issue-73427.stderr b/tests/ui/resolve/issue-73427.stderr index 622de9b39bde7..c5e245d884b7b 100644 --- a/tests/ui/resolve/issue-73427.stderr +++ b/tests/ui/resolve/issue-73427.stderr @@ -107,6 +107,10 @@ LL | (E::TupleWithFields(/* fields */)).foo(); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ help: consider importing one of these items instead | +LL + use std::f128::consts::E; + | +LL + use std::f16::consts::E; + | LL + use std::f32::consts::E; | LL + use std::f64::consts::E; diff --git a/tests/ui/resolve/privacy-enum-ctor.stderr b/tests/ui/resolve/privacy-enum-ctor.stderr index b10eded015f8c..01c8a38d2a48a 100644 --- a/tests/ui/resolve/privacy-enum-ctor.stderr +++ b/tests/ui/resolve/privacy-enum-ctor.stderr @@ -84,6 +84,10 @@ LL | let _: E = m::f; | ~ help: consider importing one of these items instead | +LL + use std::f128::consts::E; + | +LL + use std::f16::consts::E; + | LL + use std::f32::consts::E; | LL + use std::f64::consts::E; @@ -121,6 +125,10 @@ LL | let _: E = (E::Fn(/* fields */)); | ~~~~~~~~~~~~~~~~~~~~~ help: consider importing one of these items instead | +LL + use std::f128::consts::E; + | +LL + use std::f16::consts::E; + | LL + use std::f32::consts::E; | LL + use std::f64::consts::E; diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/check.rs b/tests/ui/rfcs/rfc-0000-never_patterns/check.rs index 0831477e74900..dc13dd05fa6a2 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/check.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/check.rs @@ -1,3 +1,4 @@ +// Check that never patterns can't have bodies or guards. #![feature(never_patterns)] #![allow(incomplete_features)] diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr index 25f7343a8a801..fbf7aa02ac2b9 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr +++ b/tests/ui/rfcs/rfc-0000-never_patterns/check.stderr @@ -1,5 +1,5 @@ error: a never pattern is always unreachable - --> $DIR/check.rs:14:20 + --> $DIR/check.rs:15:20 | LL | Some(!) => {} | ^^ @@ -8,13 +8,13 @@ LL | Some(!) => {} | help: remove this expression error: a guard on a never pattern will never be run - --> $DIR/check.rs:19:20 + --> $DIR/check.rs:20:20 | LL | Some(!) if true, | ^^^^ help: remove this guard error: a never pattern is always unreachable - --> $DIR/check.rs:24:28 + --> $DIR/check.rs:25:28 | LL | Some(!) if true => {} | ^^ @@ -23,7 +23,7 @@ LL | Some(!) if true => {} | help: remove this expression error: a never pattern is always unreachable - --> $DIR/check.rs:29:27 + --> $DIR/check.rs:30:27 | LL | Some(never!()) => {} | ^^ @@ -32,7 +32,7 @@ LL | Some(never!()) => {} | help: remove this expression error[E0004]: non-exhaustive patterns: `Some(!)` not covered - --> $DIR/check.rs:18:11 + --> $DIR/check.rs:19:11 | LL | match None:: { | ^^^^^^^^^^^^ pattern `Some(!)` not covered @@ -50,7 +50,7 @@ LL + Some(!) | error[E0004]: non-exhaustive patterns: `Some(!)` not covered - --> $DIR/check.rs:23:11 + --> $DIR/check.rs:24:11 | LL | match None:: { | ^^^^^^^^^^^^ pattern `Some(!)` not covered diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.rs b/tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.rs new file mode 100644 index 0000000000000..f8f9d7a9aa6ce --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.rs @@ -0,0 +1,12 @@ +#![feature(never_patterns)] +#![allow(incomplete_features)] + +enum Void {} + +fn main() {} + +fn anything() -> T { + let x: Void; + match x { ! } + //~^ ERROR used binding `x` isn't initialized +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.stderr new file mode 100644 index 0000000000000..1a6c412708579 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/check_place_is_initialized.stderr @@ -0,0 +1,16 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/check_place_is_initialized.rs:10:15 + | +LL | let x: Void; + | - binding declared here but left uninitialized +LL | match x { ! } + | ^ `x` used here but it isn't initialized + | +help: consider assigning a value + | +LL | let x: Void = /* value */; + | +++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs b/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs index e8bfa9245f597..8300f953dc162 100644 --- a/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs +++ b/tests/ui/rfcs/rfc-0000-never_patterns/typeck.rs @@ -123,3 +123,15 @@ fn never_pattern_typeck_pass(void: Void) { Some(!), } } + +struct Unsized { + void: Void, + slice: [u8], +} + +#[cfg(pass)] +fn not_sized(x: &Unsized) { + match *x { + !, + } +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.rs b/tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.rs new file mode 100644 index 0000000000000..33da6f02ce269 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.rs @@ -0,0 +1,29 @@ +//@ check-pass +#![feature(never_patterns)] +#![allow(incomplete_features)] + +#[derive(Copy, Clone)] +enum Void {} + +fn main() { + let res_void: Result = Ok(true); + + let (Ok(x) | Err(!)) = res_void; + println!("{x}"); + let (Ok(x) | Err(!)) = &res_void; + println!("{x}"); + let (Err(!) | Ok(x)) = res_void; + println!("{x}"); + + match res_void { + Ok(x) | Err(!) => println!("{x}"), + } + match res_void { + Err(!) | Ok(x) => println!("{x}"), + } + + let res_res_void: Result, Void> = Ok(Ok(true)); + match res_res_void { + Ok(Ok(x) | Err(!)) | Err(!) => println!("{x}"), + } +} diff --git a/tests/ui/rust-2018/async-ident.fixed b/tests/ui/rust-2018/async-ident.fixed index 4e31f674435b8..639a8a245fb41 100644 --- a/tests/ui/rust-2018/async-ident.fixed +++ b/tests/ui/rust-2018/async-ident.fixed @@ -9,16 +9,14 @@ fn r#async() {} //~ ERROR async macro_rules! foo { ($foo:ident) => {}; - ($r#async:expr, r#async) => {}; + ($async:expr, r#async) => {}; //~^ ERROR async - //~| ERROR async - //~| WARN this is accepted in the current edition //~| WARN this is accepted in the current edition } foo!(r#async); - //~^ ERROR async - //~| WARN this is accepted in the current edition +//~^ ERROR async +//~| WARN this is accepted in the current edition mod dont_lint_raw { fn r#async() {} diff --git a/tests/ui/rust-2018/async-ident.rs b/tests/ui/rust-2018/async-ident.rs index 4c5134a292321..7921f05f48126 100644 --- a/tests/ui/rust-2018/async-ident.rs +++ b/tests/ui/rust-2018/async-ident.rs @@ -11,14 +11,12 @@ macro_rules! foo { ($foo:ident) => {}; ($async:expr, async) => {}; //~^ ERROR async - //~| ERROR async - //~| WARN this is accepted in the current edition //~| WARN this is accepted in the current edition } foo!(async); - //~^ ERROR async - //~| WARN this is accepted in the current edition +//~^ ERROR async +//~| WARN this is accepted in the current edition mod dont_lint_raw { fn r#async() {} diff --git a/tests/ui/rust-2018/async-ident.stderr b/tests/ui/rust-2018/async-ident.stderr index 5b8d8184f4f3d..4ab061dd6f599 100644 --- a/tests/ui/rust-2018/async-ident.stderr +++ b/tests/ui/rust-2018/async-ident.stderr @@ -13,15 +13,6 @@ LL | #![deny(keyword_idents)] | ^^^^^^^^^^^^^^ = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]` -error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:12:7 - | -LL | ($async:expr, async) => {}; - | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` - | - = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #49716 - error: `async` is a keyword in the 2018 edition --> $DIR/async-ident.rs:12:19 | @@ -32,7 +23,7 @@ LL | ($async:expr, async) => {}; = note: for more information, see issue #49716 error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:19:6 + --> $DIR/async-ident.rs:17:6 | LL | foo!(async); | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -41,7 +32,7 @@ LL | foo!(async); = note: for more information, see issue #49716 error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:28:11 + --> $DIR/async-ident.rs:26:11 | LL | trait async {} | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -50,7 +41,7 @@ LL | trait async {} = note: for more information, see issue #49716 error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:32:10 + --> $DIR/async-ident.rs:30:10 | LL | impl async for MyStruct {} | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -59,7 +50,7 @@ LL | impl async for MyStruct {} = note: for more information, see issue #49716 error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:38:12 + --> $DIR/async-ident.rs:36:12 | LL | static async: u32 = 0; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -68,7 +59,7 @@ LL | static async: u32 = 0; = note: for more information, see issue #49716 error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:44:11 + --> $DIR/async-ident.rs:42:11 | LL | const async: u32 = 0; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -77,7 +68,7 @@ LL | const async: u32 = 0; = note: for more information, see issue #49716 error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:50:15 + --> $DIR/async-ident.rs:48:15 | LL | impl Foo { fn async() {} } | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -86,7 +77,7 @@ LL | impl Foo { fn async() {} } = note: for more information, see issue #49716 error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:55:12 + --> $DIR/async-ident.rs:53:12 | LL | struct async {} | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -95,7 +86,7 @@ LL | struct async {} = note: for more information, see issue #49716 error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:58:9 + --> $DIR/async-ident.rs:56:9 | LL | let async: async = async {}; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -104,7 +95,7 @@ LL | let async: async = async {}; = note: for more information, see issue #49716 error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:58:16 + --> $DIR/async-ident.rs:56:16 | LL | let async: async = async {}; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -113,7 +104,7 @@ LL | let async: async = async {}; = note: for more information, see issue #49716 error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:58:24 + --> $DIR/async-ident.rs:56:24 | LL | let async: async = async {}; | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -122,7 +113,7 @@ LL | let async: async = async {}; = note: for more information, see issue #49716 error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:69:19 + --> $DIR/async-ident.rs:67:19 | LL | () => (pub fn async() {}) | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -131,7 +122,7 @@ LL | () => (pub fn async() {}) = note: for more information, see issue #49716 error: `async` is a keyword in the 2018 edition - --> $DIR/async-ident.rs:76:6 + --> $DIR/async-ident.rs:74:6 | LL | (async) => (1) | ^^^^^ help: you can use a raw identifier to stay compatible: `r#async` @@ -139,5 +130,5 @@ LL | (async) => (1) = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #49716 -error: aborting due to 15 previous errors +error: aborting due to 14 previous errors diff --git a/tests/ui/rust-2024/gen-kw-in-macro.rs b/tests/ui/rust-2024/gen-kw-in-macro.rs new file mode 100644 index 0000000000000..3ccbe05b226bc --- /dev/null +++ b/tests/ui/rust-2024/gen-kw-in-macro.rs @@ -0,0 +1,13 @@ +//@ check-pass + +#![deny(keyword_idents_2024)] + +macro_rules! foo { + ($gen:expr) => { + $gen + }; +} + +fn main() { + foo!(println!("hello, world")); +} diff --git a/tests/ui/rust-2024/gen-kw.e2015.stderr b/tests/ui/rust-2024/gen-kw.e2015.stderr index b12363184b713..b1074f77e0089 100644 --- a/tests/ui/rust-2024/gen-kw.e2015.stderr +++ b/tests/ui/rust-2024/gen-kw.e2015.stderr @@ -22,5 +22,14 @@ LL | let gen = r#gen; = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! = note: for more information, see issue #49716 -error: aborting due to 2 previous errors +error: `gen` is a keyword in the 2024 edition + --> $DIR/gen-kw.rs:19:27 + | +LL | () => { mod test { fn gen() {} } } + | ^^^ help: you can use a raw identifier to stay compatible: `r#gen` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! + = note: for more information, see issue #49716 + +error: aborting due to 3 previous errors diff --git a/tests/ui/rust-2024/gen-kw.e2018.stderr b/tests/ui/rust-2024/gen-kw.e2018.stderr index e10fc4c45120c..b902cff7fdbc3 100644 --- a/tests/ui/rust-2024/gen-kw.e2018.stderr +++ b/tests/ui/rust-2024/gen-kw.e2018.stderr @@ -22,5 +22,14 @@ LL | let gen = r#gen; = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! = note: for more information, see issue #49716 -error: aborting due to 2 previous errors +error: `gen` is a keyword in the 2024 edition + --> $DIR/gen-kw.rs:19:27 + | +LL | () => { mod test { fn gen() {} } } + | ^^^ help: you can use a raw identifier to stay compatible: `r#gen` + | + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! + = note: for more information, see issue #49716 + +error: aborting due to 3 previous errors diff --git a/tests/ui/rust-2024/gen-kw.rs b/tests/ui/rust-2024/gen-kw.rs index 3d2a3f9516558..04251cbcac47b 100644 --- a/tests/ui/rust-2024/gen-kw.rs +++ b/tests/ui/rust-2024/gen-kw.rs @@ -14,3 +14,12 @@ fn main() { //[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! //[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! } + +macro_rules! t { + () => { mod test { fn gen() {} } } + //~^ ERROR `gen` is a keyword in the 2024 edition + //[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! + //[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024! +} + +t!(); diff --git a/tests/ui/span/macro-ty-params.rs b/tests/ui/span/macro-ty-params.rs index cf28b0255d17d..c7ce9b9faed09 100644 --- a/tests/ui/span/macro-ty-params.rs +++ b/tests/ui/span/macro-ty-params.rs @@ -11,5 +11,4 @@ fn main() { foo::<>!(); //~ ERROR generic arguments in macro path m!(Default<>); //~^ ERROR unexpected generic arguments in path - //~^^ ERROR generic arguments in macro path } diff --git a/tests/ui/span/macro-ty-params.stderr b/tests/ui/span/macro-ty-params.stderr index 7023ef8cd1c33..138cd2598a1c5 100644 --- a/tests/ui/span/macro-ty-params.stderr +++ b/tests/ui/span/macro-ty-params.stderr @@ -16,11 +16,5 @@ error: unexpected generic arguments in path LL | m!(Default<>); | ^^ -error: generic arguments in macro path - --> $DIR/macro-ty-params.rs:12:15 - | -LL | m!(Default<>); - | ^^ - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/stdlib-unit-tests/eq-multidispatch.rs b/tests/ui/stdlib-unit-tests/eq-multidispatch.rs deleted file mode 100644 index 4a991624e349d..0000000000000 --- a/tests/ui/stdlib-unit-tests/eq-multidispatch.rs +++ /dev/null @@ -1,30 +0,0 @@ -//@ run-pass - -#[derive(PartialEq, Debug)] -struct Bar; -#[derive(Debug)] -struct Baz; -#[derive(Debug)] -struct Foo; -#[derive(Debug)] -struct Fu; - -impl PartialEq for Baz { fn eq(&self, _: &Baz) -> bool { true } } - -impl PartialEq for Foo { fn eq(&self, _: &Fu) -> bool { true } } -impl PartialEq for Fu { fn eq(&self, _: &Foo) -> bool { true } } - -impl PartialEq for Foo { fn eq(&self, _: &Bar) -> bool { false } } -impl PartialEq for Bar { fn eq(&self, _: &Foo) -> bool { false } } - -fn main() { - assert!(Bar != Foo); - assert!(Foo != Bar); - - assert_eq!(Bar, Bar); - - assert_eq!(Baz, Baz); - - assert_eq!(Foo, Fu); - assert_eq!(Fu, Foo); -} diff --git a/tests/crashes/113272.rs b/tests/ui/structs/ice-struct-tail-normalization-113272.rs similarity index 66% rename from tests/crashes/113272.rs rename to tests/ui/structs/ice-struct-tail-normalization-113272.rs index d161575c657ec..85d3d1b4886f7 100644 --- a/tests/crashes/113272.rs +++ b/tests/ui/structs/ice-struct-tail-normalization-113272.rs @@ -1,9 +1,10 @@ -//@ known-bug: #113272 trait Trait { type RefTarget; } impl Trait for () where Missing: Trait {} +//~^ ERROR cannot find type `Missing` in this scope +//~| ERROR not all trait items implemented, missing: `RefTarget` struct Other { data: <() as Trait>::RefTarget, diff --git a/tests/ui/structs/ice-struct-tail-normalization-113272.stderr b/tests/ui/structs/ice-struct-tail-normalization-113272.stderr new file mode 100644 index 0000000000000..a205eb80f5c0a --- /dev/null +++ b/tests/ui/structs/ice-struct-tail-normalization-113272.stderr @@ -0,0 +1,19 @@ +error[E0412]: cannot find type `Missing` in this scope + --> $DIR/ice-struct-tail-normalization-113272.rs:5:25 + | +LL | impl Trait for () where Missing: Trait {} + | ^^^^^^^ not found in this scope + +error[E0046]: not all trait items implemented, missing: `RefTarget` + --> $DIR/ice-struct-tail-normalization-113272.rs:5:1 + | +LL | type RefTarget; + | -------------- `RefTarget` from trait +... +LL | impl Trait for () where Missing: Trait {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `RefTarget` in implementation + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0046, E0412. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/suggestions/unused-imports.fixed b/tests/ui/suggestions/unused-imports.fixed new file mode 100644 index 0000000000000..57dd091c0436d --- /dev/null +++ b/tests/ui/suggestions/unused-imports.fixed @@ -0,0 +1,35 @@ +//@ run-rustfix +//@ check-pass + +#![warn(unused_imports)] + +pub mod nested { + pub struct A; + pub struct B; + pub struct C; + pub struct D; + pub mod even_more { + pub struct E; + pub struct F; + pub struct G; + } + pub mod another { + pub struct H; + pub struct I; + } +} + +use nested::B; +//~^ WARN unused import + +use nested::even_more::F; +//~^^^^^^^ WARN unused import + +// Note that the following fix should result in `::{self}`, not `::self`. The latter is invalid +// Rust syntax, so the braces should not be removed. +use nested::another::{self}; +//~^ WARN unused import + +fn main() { + let _ = (B, F, another::I); +} diff --git a/tests/ui/suggestions/unused-imports.rs b/tests/ui/suggestions/unused-imports.rs new file mode 100644 index 0000000000000..5f9dd243bdd2a --- /dev/null +++ b/tests/ui/suggestions/unused-imports.rs @@ -0,0 +1,42 @@ +//@ run-rustfix +//@ check-pass + +#![warn(unused_imports)] + +pub mod nested { + pub struct A; + pub struct B; + pub struct C; + pub struct D; + pub mod even_more { + pub struct E; + pub struct F; + pub struct G; + } + pub mod another { + pub struct H; + pub struct I; + } +} + +use nested::{A, B, C}; +//~^ WARN unused import + +use nested::{ + D, + even_more::{ + E, + F, + G, + }, + }; +//~^^^^^^^ WARN unused import + +// Note that the following fix should result in `::{self}`, not `::self`. The latter is invalid +// Rust syntax, so the braces should not be removed. +use nested::another::{self, I}; +//~^ WARN unused import + +fn main() { + let _ = (B, F, another::I); +} diff --git a/tests/ui/suggestions/unused-imports.stderr b/tests/ui/suggestions/unused-imports.stderr new file mode 100644 index 0000000000000..bf112608da7ed --- /dev/null +++ b/tests/ui/suggestions/unused-imports.stderr @@ -0,0 +1,32 @@ +warning: unused imports: `A`, `C` + --> $DIR/unused-imports.rs:22:14 + | +LL | use nested::{A, B, C}; + | ^ ^ + | +note: the lint level is defined here + --> $DIR/unused-imports.rs:4:9 + | +LL | #![warn(unused_imports)] + | ^^^^^^^^^^^^^^ + +warning: unused imports: `D`, `E`, `G` + --> $DIR/unused-imports.rs:26:5 + | +LL | D, + | ^ +LL | even_more::{ +LL | E, + | ^ +LL | F, +LL | G, + | ^ + +warning: unused import: `I` + --> $DIR/unused-imports.rs:37:29 + | +LL | use nested::another::{self, I}; + | ^ + +warning: 3 warnings emitted + diff --git a/tests/ui/target-feature/tied-features-cli.rs b/tests/ui/target-feature/tied-features-cli.rs index 1168245461fd0..17c13826ce9e6 100644 --- a/tests/ui/target-feature/tied-features-cli.rs +++ b/tests/ui/target-feature/tied-features-cli.rs @@ -1,4 +1,4 @@ -//@ revisions: one two three +//@ revisions: one two three four //@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu //@ needs-llvm-components: aarch64 // diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.rs b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.rs new file mode 100644 index 0000000000000..26d63fdde993c --- /dev/null +++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.rs @@ -0,0 +1,9 @@ +//@ compile-flags: -Znext-solver + +#[derive(Debug)] +struct X; +//~^ ERROR using function pointers as const generic parameters is forbidden +//~| ERROR using function pointers as const generic parameters is forbidden +//~| ERROR type annotations needed + +fn main() {} diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr new file mode 100644 index 0000000000000..044c24fd2b211 --- /dev/null +++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr @@ -0,0 +1,26 @@ +error[E0282]: type annotations needed + --> $DIR/const-region-infer-to-static-in-binder.rs:4:10 + | +LL | struct X; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `{ || {} }` + +error: using function pointers as const generic parameters is forbidden + --> $DIR/const-region-infer-to-static-in-binder.rs:4:20 + | +LL | struct X; + | ^^^^ + | + = note: the only supported types are integers, `bool` and `char` + +error: using function pointers as const generic parameters is forbidden + --> $DIR/const-region-infer-to-static-in-binder.rs:4:20 + | +LL | struct X; + | ^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/next-solver/canonicalize-effect-var.rs b/tests/ui/traits/next-solver/canonical/effect-var.rs similarity index 100% rename from tests/ui/traits/next-solver/canonicalize-effect-var.rs rename to tests/ui/traits/next-solver/canonical/effect-var.rs diff --git a/tests/ui/traits/next-solver/canonical-int-var-eq-in-response.rs b/tests/ui/traits/next-solver/canonical/int-var-eq-in-response.rs similarity index 100% rename from tests/ui/traits/next-solver/canonical-int-var-eq-in-response.rs rename to tests/ui/traits/next-solver/canonical/int-var-eq-in-response.rs diff --git a/tests/ui/traits/next-solver/canonical-ty-var-eq-in-response.rs b/tests/ui/traits/next-solver/canonical/ty-var-eq-in-response.rs similarity index 100% rename from tests/ui/traits/next-solver/canonical-ty-var-eq-in-response.rs rename to tests/ui/traits/next-solver/canonical/ty-var-eq-in-response.rs diff --git a/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-1.rs b/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-1.rs new file mode 100644 index 0000000000000..151c3b226c114 --- /dev/null +++ b/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-1.rs @@ -0,0 +1,43 @@ +//@ compile-flags: -Znext-solver=coherence +//@ check-pass + +// A regression test for #124791. Computing ambiguity causes +// for the overlap of the `ToString` impls caused an ICE. +#![crate_type = "lib"] +#![feature(min_specialization)] +trait Display {} + +trait ToOwned { + type Owned; +} + +impl ToOwned for T { + type Owned = T; +} + +struct Cow(B); + +impl Display for Cow +where + B: ToOwned, + B::Owned: Display, +{ +} + +impl Display for () {} + +trait ToString { + fn to_string(); +} + +impl ToString for T { + default fn to_string() {} +} + +impl ToString for Cow { + fn to_string() {} +} + +impl ToOwned for str { + type Owned = (); +} diff --git a/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-2.rs b/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-2.rs new file mode 100644 index 0000000000000..b472499cb0bf7 --- /dev/null +++ b/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-2.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -Znext-solver=coherence + +// A regression test for #124791. Computing ambiguity causes +// for the overlap of the `ToString` impls caused an ICE. +#![crate_type = "lib"] +trait ToOwned { + type Owned; +} +impl ToOwned for T { + type Owned = u8; +} +impl ToOwned for str { + type Owned = i8; +} + +trait Overlap {} +impl + ?Sized> Overlap for T {} +impl Overlap for str {} +//~^ ERROR conflicting implementations of trait `Overlap` diff --git a/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-2.stderr b/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-2.stderr new file mode 100644 index 0000000000000..469f7a909b141 --- /dev/null +++ b/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-2.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `Overlap` for type `str` + --> $DIR/ambiguity-causes-canonical-state-ice-2.rs:18:1 + | +LL | impl + ?Sized> Overlap for T {} + | --------------------------------------------------- first implementation here +LL | impl Overlap for str {} + | ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `str` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs index 8bb4ff469076c..7eea81ce03c66 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs +++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs @@ -61,7 +61,7 @@ where // entering the cycle from `A` fails, but would work if we were to use the cache // result of `B`. impls_trait::, _, _, _>(); - //~^ ERROR the trait bound `A: Trait` is not satisfied + //~^ ERROR the trait bound `A: Trait<_, _, _>` is not satisfied } fn main() { diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.stderr b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.stderr index cdb4ff4588f75..ffa3f29e4bd6f 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.stderr +++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.stderr @@ -1,10 +1,11 @@ -error[E0277]: the trait bound `A: Trait` is not satisfied +error[E0277]: the trait bound `A: Trait<_, _, _>` is not satisfied --> $DIR/incompleteness-unstable-result.rs:63:19 | LL | impls_trait::, _, _, _>(); - | ^^^^ the trait `Trait` is not implemented for `A`, which is required by `A: Trait<_, _, _>` + | ^^^^ the trait `Trait<_, _, _>` is not implemented for `A`, which is required by `A: Trait<_, _, _>` | -note: required for `A` to implement `Trait` + = help: the trait `Trait` is implemented for `A` +note: required for `A` to implement `Trait<_, _, _>` --> $DIR/incompleteness-unstable-result.rs:32:50 | LL | impl Trait for A @@ -13,16 +14,12 @@ LL | impl Trait for A LL | A: Trait, | -------------- unsatisfied trait bound introduced here = note: 8 redundant requirements hidden - = note: required for `A` to implement `Trait` + = note: required for `A` to implement `Trait<_, _, _>` note: required by a bound in `impls_trait` --> $DIR/incompleteness-unstable-result.rs:51:28 | LL | fn impls_trait, U: ?Sized, V: ?Sized, D: ?Sized>() {} | ^^^^^^^^^^^^^^ required by this bound in `impls_trait` -help: consider extending the `where` clause, but there might be an alternative better way to express this requirement - | -LL | X: IncompleteGuidance, A: Trait - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.rs b/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.rs new file mode 100644 index 0000000000000..4737546e40487 --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.rs @@ -0,0 +1,22 @@ +trait Foo {} +trait Bar {} + +impl Foo for T where T: Bar {} +fn needs_foo(_: impl Foo) {} + +trait Mirror { + type Mirror; +} +impl Mirror for T { + type Mirror = T; +} + +// Make sure the `Alias: Foo` bound doesn't "shadow" the impl, since the +// impl is really the only candidate we care about here for the purpose +// of error reporting. +fn hello() where ::Mirror: Foo { + needs_foo(()); + //~^ ERROR the trait bound `(): Foo` is not satisfied +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr b/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr new file mode 100644 index 0000000000000..77a0cc4975412 --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/where-clause-doesnt-apply.stderr @@ -0,0 +1,22 @@ +error[E0277]: the trait bound `(): Foo` is not satisfied + --> $DIR/where-clause-doesnt-apply.rs:18:15 + | +LL | needs_foo(()); + | --------- ^^ the trait `Bar` is not implemented for `()`, which is required by `(): Foo` + | | + | required by a bound introduced by this call + | +note: required for `()` to implement `Foo` + --> $DIR/where-clause-doesnt-apply.rs:4:9 + | +LL | impl Foo for T where T: Bar {} + | ^^^ ^ --- unsatisfied trait bound introduced here +note: required by a bound in `needs_foo` + --> $DIR/where-clause-doesnt-apply.rs:5:22 + | +LL | fn needs_foo(_: impl Foo) {} + | ^^^ required by this bound in `needs_foo` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-1.rs b/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-1.rs new file mode 100644 index 0000000000000..3be118a5b3940 --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-1.rs @@ -0,0 +1,36 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass + +// Generalizing an alias referencing escaping bound variables +// is hard. We previously didn't replace this alias with inference +// variables but did replace nested alias which do not reference +// any bound variables. This caused us to stall with the following +// goal, which cannot make any progress: +// +// <::Refl as HigherRanked>::Output<'a> +// alias-relate +// ::Output<'a> +// +// +// cc trait-system-refactor-initiative#110 + +#![allow(unused)] +trait HigherRanked { + type Output<'a>; +} +trait Id { + type Refl: HigherRanked; +} + +fn foo() -> for<'a> fn(<::Refl as HigherRanked>::Output<'a>) { + todo!() +} + +fn bar() { + // we generalize here + let x = foo::(); +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-2.rs b/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-2.rs new file mode 100644 index 0000000000000..560eb34a977d8 --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/hr-alias-non-hr-alias-self-ty-2.rs @@ -0,0 +1,32 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass + +// A minimization of an ambiguity error in `icu_provider`. +// +// cc trait-system-refactor-initiative#110 + +trait Yokeable<'a> { + type Output; +} +trait Id { + type Refl; +} + +fn into_deserialized() -> M +where + M::Refl: for<'a> Yokeable<'a>, +{ + try_map_project::(|_| todo!()) +} + +fn try_map_project(_f: F) -> M +where + M::Refl: for<'a> Yokeable<'a>, + F: for<'a> FnOnce(&'a ()) -> <::Refl as Yokeable<'a>>::Output, +{ + todo!() +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/generalize/hr-alias-universe-lowering-ambiguity.rs b/tests/ui/traits/next-solver/generalize/hr-alias-universe-lowering-ambiguity.rs new file mode 100644 index 0000000000000..1e2ba81129dba --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/hr-alias-universe-lowering-ambiguity.rs @@ -0,0 +1,51 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// A regression test for a fairly subtle issue with how we +// generalize aliases referencing higher-ranked regions +// which previously caused unexpected ambiguity errors. +// +// The explanations in the test may end up being out of date +// in the future as we may refine our approach to generalization +// going forward. +// +// cc trait-system-refactor-initiative#108 +trait Trait<'a> { + type Assoc; +} + +impl<'a> Trait<'a> for () { + type Assoc = (); +} + +fn foo Trait<'a>>(x: T) -> for<'a> fn(>::Assoc) { + |_| () +} + +fn unconstrained() -> T { + todo!() +} + +fn main() { + // create `?x.0` in the root universe + let mut x = unconstrained(); + + // bump the current universe of the inference context + let bump: for<'a, 'b> fn(&'a (), &'b ()) = |_, _| (); + let _: for<'a> fn(&'a (), &'a ()) = bump; + + // create `?y.1` in a higher universe + let mut y = Default::default(); + + // relate `?x.0` with `for<'a> fn(>::Assoc)` + // -> instantiate `?x.0` with `for<'a> fn(>::Assoc)` + x = foo(y); + + // Constrain `?y.1` to `()` + let _: () = y; + + // `AliasRelate(>::Assoc, <() as Trait<'a>>::Assoc)` + // remains ambiguous unless we somehow constrain `?y_new.0` during + // generalization to be equal to `?y.1`, which is exactly what we + // did to fix this issue. +} diff --git a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs index 536e7e97c40de..00dc7a9d337d9 100644 --- a/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs +++ b/tests/ui/traits/next-solver/generalize/occurs-check-nested-alias.rs @@ -1,5 +1,6 @@ //@ revisions: old next //@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) //@ check-pass // case 3 of https://github.com/rust-lang/trait-system-refactor-initiative/issues/8. diff --git a/tests/ui/traits/next-solver/select-alias-bound-as-param.rs b/tests/ui/traits/next-solver/select-alias-bound-as-param.rs new file mode 100644 index 0000000000000..fd40ef1f872f3 --- /dev/null +++ b/tests/ui/traits/next-solver/select-alias-bound-as-param.rs @@ -0,0 +1,13 @@ +//@ check-pass +//@ compile-flags: -Znext-solver + +pub(crate) fn y() -> impl FnMut() { + || {} +} + +pub(crate) fn x(a: (), b: ()) { + let x = (); + y()() +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/typeck/normalize-in-upvar-collection.rs b/tests/ui/traits/next-solver/typeck/normalize-in-upvar-collection.rs new file mode 100644 index 0000000000000..6567f2752404a --- /dev/null +++ b/tests/ui/traits/next-solver/typeck/normalize-in-upvar-collection.rs @@ -0,0 +1,19 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Fixes a regression in icu_provider_adaptors where we weren't normalizing the +// return type of a function type before performing a `Ty::builtin_deref` call, +// leading to an ICE. + +struct Struct { + field: i32, +} + +fn hello(f: impl Fn() -> &'static Box<[i32]>, f2: impl Fn() -> &'static Struct) { + let cl = || { + let x = &f()[0]; + let y = &f2().field; + }; +} + +fn main() {} diff --git a/tests/ui/traits/normalize-supertrait.rs b/tests/ui/traits/normalize-supertrait.rs index 1ab2b8ecfc108..3ba4a8b8bab31 100644 --- a/tests/ui/traits/normalize-supertrait.rs +++ b/tests/ui/traits/normalize-supertrait.rs @@ -4,6 +4,9 @@ // comparing the supertrait `Derived<()>` to the expected trait. //@ build-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver trait Proj { type S; diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr deleted file mode 100644 index 3c2bc0b919065..0000000000000 --- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: internal compiler error: error performing operation: query type op - --> $DIR/illegal-upcast-from-impl-opaque.rs:25:1 - | -LL | fn illegal(x: &dyn Sub) -> &dyn Super { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: - --> $DIR/illegal-upcast-from-impl-opaque.rs:25:1 - | -LL | fn illegal(x: &dyn Sub) -> &dyn Super { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -query stack during panic: -end of query stack diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs deleted file mode 100644 index f344474054a22..0000000000000 --- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs +++ /dev/null @@ -1,29 +0,0 @@ -//@ revisions: current next -//@[next] compile-flags: -Znext-solver -//@[next] failure-status: 101 -//@[next] known-bug: unknown -//@[next] normalize-stderr-test "note: .*\n\n" -> "" -//@[next] normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> "" -//@[next] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " -//@[next] normalize-stderr-test "delayed at .*" -> "" -//@[next] rustc-env:RUST_BACKTRACE=0 - -#![feature(trait_upcasting, type_alias_impl_trait)] - -trait Super { - type Assoc; -} - -trait Sub: Super {} - -impl Super for T { - type Assoc = i32; -} - -type Foo = impl Sized; - -fn illegal(x: &dyn Sub) -> &dyn Super { - x //[current]~ mismatched types -} - -fn main() {} diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr b/tests/ui/traits/trait-upcasting/upcast-defining-opaque.current.stderr similarity index 62% rename from tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr rename to tests/ui/traits/trait-upcasting/upcast-defining-opaque.current.stderr index c54a1c42baddf..a259abb28ae3e 100644 --- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr +++ b/tests/ui/traits/trait-upcasting/upcast-defining-opaque.current.stderr @@ -1,11 +1,11 @@ error[E0308]: mismatched types - --> $DIR/illegal-upcast-from-impl-opaque.rs:26:5 + --> $DIR/upcast-defining-opaque.rs:21:5 | LL | type Foo = impl Sized; | ---------- the found opaque type LL | -LL | fn illegal(x: &dyn Sub) -> &dyn Super { - | ----------------------- expected `&dyn Super` because of return type +LL | fn upcast(x: &dyn Sub) -> &dyn Super { + | ----------------------- expected `&dyn Super` because of return type LL | x | ^ expected trait `Super`, found trait `Sub` | diff --git a/tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs b/tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs new file mode 100644 index 0000000000000..cb1501a94a2ae --- /dev/null +++ b/tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs @@ -0,0 +1,24 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] check-pass + +#![feature(trait_upcasting, type_alias_impl_trait)] + +trait Super { + type Assoc; +} + +trait Sub: Super {} + +impl Super for T { + type Assoc = i32; +} + +type Foo = impl Sized; + +fn upcast(x: &dyn Sub) -> &dyn Super { + x //[current]~ mismatched types +} + +fn main() {} diff --git a/tests/ui/transmutability/primitives/bool-mut.rs b/tests/ui/transmutability/primitives/bool-mut.rs index 5f3f4f3a8c5b4..09b6d582d871c 100644 --- a/tests/ui/transmutability/primitives/bool-mut.rs +++ b/tests/ui/transmutability/primitives/bool-mut.rs @@ -1,5 +1,4 @@ //@ check-fail -//@[next] compile-flags: -Znext-solver #![feature(transmutability)] mod assert { diff --git a/tests/ui/transmutability/primitives/bool-mut.stderr b/tests/ui/transmutability/primitives/bool-mut.stderr index 464c2755e11b6..a6cf146659e62 100644 --- a/tests/ui/transmutability/primitives/bool-mut.stderr +++ b/tests/ui/transmutability/primitives/bool-mut.stderr @@ -1,11 +1,11 @@ error[E0277]: `u8` cannot be safely transmuted into `bool` - --> $DIR/bool-mut.rs:15:50 + --> $DIR/bool-mut.rs:14:50 | LL | assert::is_transmutable::<&'static mut bool, &'static mut u8>() | ^^^^^^^^^^^^^^^ at least one value of `u8` isn't a bit-valid value of `bool` | note: required by a bound in `is_transmutable` - --> $DIR/bool-mut.rs:10:14 + --> $DIR/bool-mut.rs:9:14 | LL | pub fn is_transmutable() | --------------- required by a bound in this function diff --git a/tests/ui/type-alias-impl-trait/static-lifetime-through-closure-issue-122775.rs b/tests/ui/type-alias-impl-trait/static-lifetime-through-closure-issue-122775.rs new file mode 100644 index 0000000000000..1bb0acf9b754e --- /dev/null +++ b/tests/ui/type-alias-impl-trait/static-lifetime-through-closure-issue-122775.rs @@ -0,0 +1,17 @@ +//@ check-pass + +#![feature(type_alias_impl_trait)] + +fn spawn(future: F) -> impl Sized +where + F: FnOnce() -> T, +{ + future +} + +fn spawn_task(sender: &'static ()) -> impl Sized { + type Tait = impl Sized + 'static; + spawn::(move || sender) +} + +fn main() {} diff --git a/tests/ui/type/pattern_types/range_patterns_usage.rs b/tests/ui/type/pattern_types/range_patterns_usage.rs index 7fe50423c511b..2a9f736ae61d5 100644 --- a/tests/ui/type/pattern_types/range_patterns_usage.rs +++ b/tests/ui/type/pattern_types/range_patterns_usage.rs @@ -8,7 +8,7 @@ use std::pat::pattern_type; -type X = std::num::NonZeroU32; +type X = std::num::NonZero; type Y = pattern_type!(u32 is 1..); type Z = Option; struct NonZeroU32New(pattern_type!(u32 is 1..)); diff --git a/tests/ui/unpretty/pretty-let-else.rs b/tests/ui/unpretty/let-else-hir.rs similarity index 100% rename from tests/ui/unpretty/pretty-let-else.rs rename to tests/ui/unpretty/let-else-hir.rs diff --git a/tests/ui/unpretty/pretty-let-else.stdout b/tests/ui/unpretty/let-else-hir.stdout similarity index 100% rename from tests/ui/unpretty/pretty-let-else.stdout rename to tests/ui/unpretty/let-else-hir.stdout diff --git a/tests/ui/unpretty/let-else.rs b/tests/ui/unpretty/let-else.rs new file mode 100644 index 0000000000000..4db6eca99b18f --- /dev/null +++ b/tests/ui/unpretty/let-else.rs @@ -0,0 +1,11 @@ +//@ compile-flags: -Zunpretty=expanded +//@ check-pass + +macro_rules! expr { + ($e:expr) => { $e }; +} + +fn main() { + let _ = expr!(1 + 1) else { return; }; + let _ = expr!(loop {}) else { return; }; +} diff --git a/tests/ui/unpretty/let-else.stdout b/tests/ui/unpretty/let-else.stdout new file mode 100644 index 0000000000000..4bc4d9e085f97 --- /dev/null +++ b/tests/ui/unpretty/let-else.stdout @@ -0,0 +1,15 @@ +#![feature(prelude_import)] +#![no_std] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; +//@ compile-flags: -Zunpretty=expanded +//@ check-pass + +macro_rules! expr { ($e:expr) => { $e }; } + +fn main() { + let _ = 1 + 1 else { return; }; + let _ = (loop {}) else { return; }; +} diff --git a/tests/ui/version/version-info-flags.rs b/tests/ui/version/version-info-flags.rs index 612113452c41f..96be9c5385b28 100644 --- a/tests/ui/version/version-info-flags.rs +++ b/tests/ui/version/version-info-flags.rs @@ -4,6 +4,6 @@ //@ check-pass //@[version] compile-flags: -V //@[verbose-version] compile-flags: -vV -//@[long-verbose-verison] compile-flags: --version --verbose +//@[long-verbose-version] compile-flags: --version --verbose fn main() {} diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs new file mode 100644 index 0000000000000..2995f26af4a61 --- /dev/null +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs @@ -0,0 +1,21 @@ +// Regression test for ICE #122989 +trait Foo> { +//~^ WARN trait objects without an explicit `dyn` are deprecated +//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! +//~| ERROR cycle detected when computing type of `Foo::N` +//~| ERROR cycle detected when computing type of `Foo::N` +//~| ERROR the trait `Foo` cannot be made into an object +//~| ERROR the trait `Foo` cannot be made into an object +//~| ERROR the trait `Foo` cannot be made into an object +//~| ERROR `(dyn Bar<2> + 'static)` is forbidden as the type of a const generic parameter + fn func() { + } +} + +trait Bar> {} +//~^ WARN trait objects without an explicit `dyn` are deprecated +//~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! +//~| ERROR the trait `Foo` cannot be made into an object +//~| ERROR `(dyn Foo<2> + 'static)` is forbidden as the type of a const generic parameter + +fn main() {} diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr new file mode 100644 index 0000000000000..e6fdc44087364 --- /dev/null +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr @@ -0,0 +1,179 @@ +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:2:20 + | +LL | trait Foo> { + | ^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `#[warn(bare_trait_objects)]` on by default +help: if this is an object-safe trait, use `dyn` + | +LL | trait Foo> { + | +++ + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:15:20 + | +LL | trait Bar> {} + | ^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see +help: if this is an object-safe trait, use `dyn` + | +LL | trait Bar> {} + | +++ + +error[E0391]: cycle detected when computing type of `Foo::N` + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:2:11 + | +LL | trait Foo> { + | ^^^^^^^^^^^^^^^ + | +note: ...which requires computing type of `Bar::M`... + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:15:11 + | +LL | trait Bar> {} + | ^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `Foo::N`, completing the cycle +note: cycle used when computing explicit predicates of trait `Foo` + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:2:1 + | +LL | trait Foo> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0391]: cycle detected when computing type of `Foo::N` + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:2:11 + | +LL | trait Foo> { + | ^^^^^^^^^^^^^^^ + | +note: ...which requires computing type of `Bar::M`... + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:15:11 + | +LL | trait Bar> {} + | ^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `Foo::N`, completing the cycle +note: cycle used when computing explicit predicates of trait `Foo` + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:2:1 + | +LL | trait Foo> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = 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 + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:2:24 + | +LL | trait Foo> { + | ^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:8 + | +LL | trait Foo> { + | --- this trait cannot be made into an object... +... +LL | fn func() { + | ^^^^ ...because associated function `func` has no `self` parameter +help: consider turning `func` into a method by giving it a `&self` argument + | +LL | fn func(&self) { + | +++++ +help: alternatively, consider constraining `func` so it does not apply to trait objects + | +LL | fn func() where Self: Sized { + | +++++++++++++++++ + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:2:11 + | +LL | trait Foo> { + | ^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:8 + | +LL | trait Foo> { + | --- this trait cannot be made into an object... +... +LL | fn func() { + | ^^^^ ...because associated function `func` has no `self` parameter +help: consider turning `func` into a method by giving it a `&self` argument + | +LL | fn func(&self) { + | +++++ +help: alternatively, consider constraining `func` so it does not apply to trait objects + | +LL | fn func() where Self: Sized { + | +++++++++++++++++ + +error: `(dyn Bar<2> + 'static)` is forbidden as the type of a const generic parameter + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:2:20 + | +LL | trait Foo> { + | ^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:15:11 + | +LL | trait Bar> {} + | ^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:8 + | +LL | trait Foo> { + | --- this trait cannot be made into an object... +... +LL | fn func() { + | ^^^^ ...because associated function `func` has no `self` parameter +help: consider turning `func` into a method by giving it a `&self` argument + | +LL | fn func(&self) { + | +++++ +help: alternatively, consider constraining `func` so it does not apply to trait objects + | +LL | fn func() where Self: Sized { + | +++++++++++++++++ + +error: `(dyn Foo<2> + 'static)` is forbidden as the type of a const generic parameter + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:15:20 + | +LL | trait Bar> {} + | ^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:2:11 + | +LL | trait Foo> { + | ^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:8 + | +LL | trait Foo> { + | --- this trait cannot be made into an object... +... +LL | fn func() { + | ^^^^ ...because associated function `func` has no `self` parameter + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider turning `func` into a method by giving it a `&self` argument + | +LL | fn func(&self) { + | +++++ +help: alternatively, consider constraining `func` so it does not apply to trait objects + | +LL | fn func() where Self: Sized { + | +++++++++++++++++ + +error: aborting due to 8 previous errors; 2 warnings emitted + +Some errors have detailed explanations: E0038, E0391. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/write-fmt-errors.rs b/tests/ui/write-fmt-errors.rs index f194e25b5567c..1dafb9a784b3a 100644 --- a/tests/ui/write-fmt-errors.rs +++ b/tests/ui/write-fmt-errors.rs @@ -1,9 +1,11 @@ //@ run-pass +//@ needs-unwind #![feature(io_error_uncategorized)] use std::fmt; use std::io::{self, Error, Write, sink}; +use std::panic::catch_unwind; struct ErrorDisplay; @@ -15,7 +17,6 @@ impl fmt::Display for ErrorDisplay { struct ErrorWriter; -const FORMAT_ERROR: io::ErrorKind = io::ErrorKind::Uncategorized; const WRITER_ERROR: io::ErrorKind = io::ErrorKind::NotConnected; impl Write for ErrorWriter { @@ -27,22 +28,28 @@ impl Write for ErrorWriter { } fn main() { - // Test that the error from the formatter is propagated. - let res = write!(sink(), "{} {} {}", 1, ErrorDisplay, "bar"); - assert!(res.is_err(), "formatter error did not propagate"); - assert_eq!(res.unwrap_err().kind(), FORMAT_ERROR); - // Test that an underlying error is propagated let res = write!(ErrorWriter, "abc"); assert!(res.is_err(), "writer error did not propagate"); - // Writer error + // Test that the error from the formatter is detected. + let res = catch_unwind(|| write!(sink(), "{} {} {}", 1, ErrorDisplay, "bar")); + let err = res.expect_err("formatter error did not lead to panic").downcast::<&str>().unwrap(); + assert!( + err.contains("formatting trait implementation returned an error"), + "unexpected panic: {}", err + ); + + // Writer error when there's some string before the first `{}` let res = write!(ErrorWriter, "abc {}", ErrorDisplay); assert!(res.is_err(), "writer error did not propagate"); assert_eq!(res.unwrap_err().kind(), WRITER_ERROR); - // Formatter error - let res = write!(ErrorWriter, "{} abc", ErrorDisplay); - assert!(res.is_err(), "formatter error did not propagate"); - assert_eq!(res.unwrap_err().kind(), FORMAT_ERROR); + // Formatter error when the `{}` comes first + let res = catch_unwind(|| write!(ErrorWriter, "{} abc", ErrorDisplay)); + let err = res.expect_err("formatter error did not lead to panic").downcast::<&str>().unwrap(); + assert!( + err.contains("formatting trait implementation returned an error"), + "unexpected panic: {}", err + ); } diff --git a/triagebot.toml b/triagebot.toml index dd6a03faaaffd..3d22da56f7c75 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -310,7 +310,7 @@ trigger_files = [ "configure", "Cargo.toml", "config.example.toml", - "src/stage0.json", + "src/stage0", "src/tools/compiletest", "src/tools/tidy", "src/tools/rustdoc-gui-test", @@ -370,7 +370,7 @@ trigger_files = [ [autolabel."T-release"] trigger_files = [ "RELEASES.md", - "src/stage0.json", + "src/stage0", "src/version" ] @@ -933,11 +933,13 @@ arena = [ mir = [ "@davidtwco", "@oli-obk", - "@matthewjasper" + "@matthewjasper", + "@saethlin", ] mir-opt = [ "@oli-obk", "@wesleywiser", + "@saethlin", ] types = [ "@compiler-errors", @@ -1003,6 +1005,7 @@ project-exploit-mitigations = [ "/compiler/rustc_lexer" = ["compiler", "lexer"] "/compiler/rustc_llvm" = ["@cuviper"] "/compiler/rustc_codegen_llvm/src/debuginfo" = ["compiler", "debuginfo"] +"/compiler/rustc_codegen_ssa" = ["compiler", "@saethlin"] "/compiler/rustc_middle/src/mir" = ["compiler", "mir"] "/compiler/rustc_middle/src/traits" = ["compiler", "types"] "/compiler/rustc_middle/src/ty" = ["compiler", "types"] @@ -1046,7 +1049,7 @@ project-exploit-mitigations = [ "/src/librustdoc" = ["rustdoc"] "/src/llvm-project" = ["@cuviper"] "/src/rustdoc-json-types" = ["rustdoc"] -"/src/stage0.json" = ["bootstrap"] +"/src/stage0" = ["bootstrap"] "/tests/run-make" = ["@jieyouxu"] "/tests/ui" = ["compiler"] "/src/tools/cargo" = ["@ehuss"]