diff options
1417 files changed, 18751 insertions, 12558 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c9d6c56076a..521f8ef0f5a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,6 +38,8 @@ concurrency: cancel-in-progress: true env: TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate" + # This will be empty in PR jobs. + TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }} jobs: # The job matrix for `calculate_matrix` is defined in src/ci/github-actions/jobs.yml. # It calculates which jobs should be executed, based on the data of the ${{ github }} context. @@ -154,12 +156,6 @@ jobs: - name: checkout submodules run: src/ci/scripts/checkout-submodules.sh - - - name: Setup Python - uses: actions/setup-python@v5 - with: - python-version: '3.x' - if: runner.environment == 'github-hosted' - name: install MinGW run: src/ci/scripts/install-mingw.sh @@ -242,6 +238,5 @@ jobs: shell: bash if: needs.calculate_matrix.outputs.run_type == 'auto' env: - TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }} TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues TOOLSTATE_PUBLISH: 1 diff --git a/Cargo.lock b/Cargo.lock index 1018eac13ff..ba8b2c27005 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,9 +131,9 @@ dependencies = [ [[package]] name = "annotate-snippets" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5a59f105fb9635e9eebdc1e29d53e764fa5795b9cf899a638a53e61567ef61" +checksum = "086b0afab3b349e5691143adbfb26983821e3eec4ba4c51957104d372c2e1b7d" dependencies = [ "anstyle", "unicode-width", @@ -189,9 +189,9 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" dependencies = [ "windows-sys 0.52.0", ] @@ -266,7 +266,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -372,7 +372,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" dependencies = [ "memchr", - "regex-automata 0.3.9", + "regex-automata 0.3.7", "serde", ] @@ -501,9 +501,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.97" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" [[package]] name = "cfg-if" @@ -568,9 +568,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "a9689a29b593160de5bc4aacab7b5d54fb52231de70122626c178e6a368994c7" dependencies = [ "clap_builder", "clap_derive", @@ -588,9 +588,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "2e5387378c84f6faa26890ebf9f0a92989f8873d4d380467bcd0d8d8620424df" dependencies = [ "anstream", "anstyle", @@ -601,30 +601,30 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.2" +version = "4.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79504325bf38b10165b02e89b4347300f855f273c4cb30c4a3209e6583275e" +checksum = "d2020fa13af48afc65a9a87335bda648309ab3d154cd03c7ff95b378c7ed39c4" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "clippy" @@ -644,7 +644,7 @@ dependencies = [ "regex", "rustc_tools_util", "serde", - "syn 2.0.64", + "syn 2.0.66", "tempfile", "termize", "tokio", @@ -754,7 +754,7 @@ dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -878,18 +878,18 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ "crossbeam-utils", ] @@ -915,9 +915,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-common" @@ -990,7 +990,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1001,7 +1001,7 @@ checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ "darling_core", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1027,7 +1027,7 @@ version = "0.1.80" dependencies = [ "itertools 0.12.1", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1068,7 +1068,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1078,7 +1078,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" dependencies = [ "derive_builder_core", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1101,7 +1101,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1196,7 +1196,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1516,7 +1516,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1588,9 +1588,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -1757,7 +1757,7 @@ dependencies = [ "markup5ever 0.12.1", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1800,9 +1800,9 @@ dependencies = [ [[package]] name = "icu_list" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe6c04ec71ad1bacdbfb47164d4801f80a0533d9340f94f1a880f521eff59f54" +checksum = "bbfeda1d7775b6548edd4e8b7562304a559a91ed56ab56e18961a053f367c365" dependencies = [ "displaydoc", "icu_list_data", @@ -1814,15 +1814,15 @@ dependencies = [ [[package]] name = "icu_list_data" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f6afcf7a9a7fedece70b7f17d7a7ecdfb8df145d37ae46d0277cd1e3932532" +checksum = "e1825170d2c6679cb20dbd96a589d034e49f698aed9a2ef4fafc9a0101ed298f" [[package]] name = "icu_locid" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c0aa2536adc14c07e2a521e95512b75ed8ef832f0fdf9299d4a0a45d2be2a9d" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ "displaydoc", "litemap", @@ -1833,9 +1833,9 @@ dependencies = [ [[package]] name = "icu_locid_transform" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c17d8f6524fdca4471101dd71f0a132eb6382b5d6d7f2970441cb25f6f435a" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" dependencies = [ "displaydoc", "icu_locid", @@ -1847,15 +1847,15 @@ dependencies = [ [[package]] name = "icu_locid_transform_data" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545c6c3e8bf9580e2dafee8de6f9ec14826aaf359787789c7724f1f85f47d3dc" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" [[package]] name = "icu_provider" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba58e782287eb6950247abbf11719f83f5d4e4a5c1f2cd490d30a334bc47c2f4" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" dependencies = [ "displaydoc", "icu_locid", @@ -1870,9 +1870,9 @@ dependencies = [ [[package]] name = "icu_provider_adapters" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a229f978260da7c3aabb68cb7dc7316589936680570fe55e50fdd3f97711a4dd" +checksum = "d6324dfd08348a8e0374a447ebd334044d766b1839bb8d5ccf2482a99a77c0bc" dependencies = [ "icu_locid", "icu_locid_transform", @@ -1883,13 +1883,13 @@ dependencies = [ [[package]] name = "icu_provider_macros" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2abdd3a62551e8337af119c5899e600ca0c88ec8f23a46c60ba216c803dcf1a" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -2196,9 +2196,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.16" +version = "1.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" +checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" dependencies = [ "cc", "libc", @@ -2207,6 +2207,21 @@ dependencies = [ ] [[package]] +name = "line-wrap" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd1bc4d24ad230d21fb898d1116b1801d7adfc449d42026475862ab48b11e70e" + +[[package]] +name = "linereader" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d921fea6860357575519aca014c6e22470585accdd543b370c404a8a72d0dd1d" +dependencies = [ + "memchr", +] + +[[package]] name = "linkchecker" version = "0.1.0" dependencies = [ @@ -2215,6 +2230,12 @@ dependencies = [ ] [[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] name = "lint-docs" version = "0.1.0" dependencies = [ @@ -2231,9 +2252,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "litemap" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d642685b028806386b2b6e75685faadd3eb65a85fff7df711ce18446a422da" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" [[package]] name = "lld-wrapper" @@ -2365,6 +2386,25 @@ dependencies = [ ] [[package]] +name = "mdbook-i18n-helpers" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f71f5961d6f3376e1ff3e5989c2e3ecccc3e8a00f3a3acde446847f84852e4" +dependencies = [ + "anyhow", + "chrono", + "mdbook", + "polib", + "pulldown-cmark 0.10.3", + "pulldown-cmark-to-cmark", + "regex", + "semver", + "serde_json", + "syntect", + "textwrap", +] + +[[package]] name = "mdbook-trpl-listing" version = "0.1.0" dependencies = [ @@ -2375,7 +2415,7 @@ dependencies = [ "pulldown-cmark-to-cmark", "serde_json", "thiserror", - "toml 0.8.13", + "toml 0.8.14", "xmlparser", ] @@ -2568,9 +2608,9 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.49.0" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c073d3c1930d0751774acf49e66653acecb416c3a54c6ec095a9b11caddb5a68" +checksum = "dd2800e1520bdc966782168a627aa5d1ad92e33b984bf7c7615d31280c83ff14" dependencies = [ "windows-sys 0.48.0", ] @@ -2612,14 +2652,11 @@ version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ - "compiler_builtins", "crc32fast", "flate2", "hashbrown", "indexmap", "memchr", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", "ruzstd 0.5.0", "wasmparser", ] @@ -2636,6 +2673,18 @@ dependencies = [ ] [[package]] +name = "object" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" +dependencies = [ + "compiler_builtins", + "memchr", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] name = "odht" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2651,6 +2700,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] +name = "onig" +version = "6.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" +dependencies = [ + "bitflags 1.3.2", + "libc", + "once_cell", + "onig_sys", +] + +[[package]] +name = "onig_sys" +version = "69.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] name = "opener" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2778,9 +2849,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -2860,7 +2931,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -2969,6 +3040,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] +name = "plist" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9d34169e64b3c7a80c8621a48adaf44e0cf62c78a9b25dd9dd35f1881a17cf9" +dependencies = [ + "base64", + "indexmap", + "line-wrap", + "quick-xml", + "serde", + "time", +] + +[[package]] +name = "polib" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b393b155cf9be86249cba1b56cc81be0e6212c66d94ac0d76d37a1761f3bb1b" +dependencies = [ + "linereader", +] + +[[package]] name = "polonius-engine" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3048,9 +3142,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] @@ -3127,6 +3221,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9e1dcb320d6839f6edb64f7a4a59d39b30480d4d1765b56873f7c858538a5fe" [[package]] +name = "quick-xml" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", +] + +[[package]] name = "quine-mc_cluskey" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3143,9 +3246,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "4.4.0" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c47196f636c4cc0634b73b0405323d177753c2e15e866952c64ea22902567a34" +checksum = "e9e935efc5854715dfc0a4c9ef18dc69dee0ec3bf9cc3ab740db831c0fdd86a3" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -3261,12 +3364,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.4" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" dependencies = [ "aho-corasick", "memchr", + "regex-automata 0.3.7", "regex-syntax 0.7.5", ] @@ -3290,9 +3394,14 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.9" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.7.5", +] [[package]] name = "regex-lite" @@ -3367,6 +3476,7 @@ dependencies = [ "clap", "env_logger", "mdbook", + "mdbook-i18n-helpers", "mdbook-trpl-listing", "mdbook-trpl-note", ] @@ -3517,7 +3627,6 @@ dependencies = [ "rustc_macros", "rustc_serialize", "rustc_span", - "smallvec", ] [[package]] @@ -3598,7 +3707,6 @@ dependencies = [ "icu_locid", "icu_locid_transform", "icu_provider", - "icu_provider_adapters", "zerovec", ] @@ -3779,7 +3887,6 @@ dependencies = [ "portable-atomic", "rustc-hash", "rustc-rayon", - "rustc-rayon-core", "rustc_arena", "rustc_graphviz", "rustc_index", @@ -3820,7 +3927,6 @@ dependencies = [ "rustc_expand", "rustc_feature", "rustc_fluent_macro", - "rustc_hir", "rustc_hir_analysis", "rustc_hir_pretty", "rustc_hir_typeck", @@ -3948,7 +4054,7 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "unic-langid", ] @@ -4082,8 +4188,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", - "synstructure", + "syn 2.0.66", ] [[package]] @@ -4100,6 +4205,7 @@ dependencies = [ "rustc_middle", "rustc_span", "rustc_target", + "rustc_type_ir", "smallvec", "tracing", ] @@ -4230,7 +4336,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "synstructure", ] @@ -4274,7 +4380,6 @@ dependencies = [ "field-offset", "gsgdt", "polonius-engine", - "rustc-rayon", "rustc-rayon-core", "rustc_apfloat", "rustc_arena", @@ -4291,7 +4396,6 @@ dependencies = [ "rustc_hir_pretty", "rustc_index", "rustc_macros", - "rustc_next_trait_solver", "rustc_query_system", "rustc_serialize", "rustc_session", @@ -4307,7 +4411,6 @@ dependencies = [ name = "rustc_mir_build" version = "0.0.0" dependencies = [ - "either", "itertools 0.12.1", "rustc_apfloat", "rustc_arena", @@ -4326,7 +4429,6 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_trait_selection", - "smallvec", "tracing", ] @@ -4401,13 +4503,7 @@ dependencies = [ name = "rustc_next_trait_solver" version = "0.0.0" dependencies = [ - "derivative", - "rustc_ast_ir", - "rustc_data_structures", - "rustc_macros", - "rustc_serialize", "rustc_type_ir", - "rustc_type_ir_macros", ] [[package]] @@ -4512,7 +4608,6 @@ version = "0.0.0" dependencies = [ "field-offset", "measureme", - "rustc-rayon-core", "rustc_data_structures", "rustc_errors", "rustc_hir", @@ -4809,7 +4904,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "synstructure", ] @@ -4907,7 +5002,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -5043,22 +5138,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -5170,9 +5265,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccdf4f5590b7e6fbd4f2e80d442789079a6fff7c12ef921a9de358b7b353098e" +checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" dependencies = [ "bstr", "color-eyre", @@ -5218,7 +5313,6 @@ name = "stable_mir" version = "0.1.0-preview" dependencies = [ "scoped-tls", - "tracing", ] [[package]] @@ -5255,7 +5349,7 @@ dependencies = [ "hermit-abi", "libc", "miniz_oxide", - "object 0.32.2", + "object 0.36.0", "panic_abort", "panic_unwind", "profiler_builtins", @@ -5352,9 +5446,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.64" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -5369,7 +5463,29 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", +] + +[[package]] +name = "syntect" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1" +dependencies = [ + "bincode", + "bitflags 1.3.2", + "flate2", + "fnv", + "once_cell", + "onig", + "plist", + "regex-syntax 0.8.3", + "serde", + "serde_derive", + "serde_json", + "thiserror", + "walkdir", + "yaml-rust", ] [[package]] @@ -5407,9 +5523,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" dependencies = [ "filetime", "libc", @@ -5492,12 +5608,16 @@ dependencies = [ "core", "getopts", "libc", - "panic_abort", - "panic_unwind", "std", ] [[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" + +[[package]] name = "thin-vec" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5520,7 +5640,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -5605,9 +5725,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c02bf3c538ab32ba913408224323915f4ef9a6d61c0e85d493f355921c0ece" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ "displaydoc", "zerovec", @@ -5630,9 +5750,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", @@ -5662,14 +5782,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.13" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.13", + "toml_edit 0.22.14", ] [[package]] @@ -5696,15 +5816,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.13" +version = "0.22.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.8", + "winnow 0.6.13", ] [[package]] @@ -5733,7 +5853,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -5788,11 +5908,11 @@ dependencies = [ [[package]] name = "tracing-tree" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65139ecd2c3f6484c3b99bc01c77afe21e95473630747c7aca525e78b0666675" +checksum = "b56c62d2c80033cb36fae448730a2f2ef99410fe3ecbffc916681a32f6807dbe" dependencies = [ - "nu-ansi-term 0.49.0", + "nu-ansi-term 0.50.0", "tracing-core", "tracing-log", "tracing-subscriber", @@ -5872,7 +5992,7 @@ version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29e5f4ffcbab82453958fbf59990e981b8e8a177dcd60c2bd8f9b52c3036a6e1" dependencies = [ - "annotate-snippets 0.11.2", + "annotate-snippets 0.11.3", "anyhow", "bstr", "cargo-platform", @@ -5933,7 +6053,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.64", + "syn 2.0.66", "unic-langid-impl", ] @@ -6004,9 +6124,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -6083,9 +6203,9 @@ checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" @@ -6165,7 +6285,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "wasm-bindgen-shared", ] @@ -6187,7 +6307,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6268,7 +6388,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "syn 2.0.64", + "syn 2.0.66", "windows-metadata", ] @@ -6437,18 +6557,18 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.8" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" dependencies = [ "memchr", ] [[package]] name = "writeable" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad7bb64b8ef9c0aa27b6da38b452b0ee9fd82beaf276a87dd796fb55cbae14e" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "xattr" @@ -6477,6 +6597,15 @@ dependencies = [ ] [[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + +[[package]] name = "yansi-term" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6487,9 +6616,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e71b2e4f287f467794c671e2b8f8a5f3716b3c829079a1c44740148eff07e4" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" dependencies = [ "serde", "stable_deref_trait", @@ -6499,13 +6628,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e6936f0cce458098a201c245a11bef556c6a0181129c7034d10d76d1ec3a2b8" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "synstructure", ] @@ -6526,35 +6655,35 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] name = "zerofrom" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655b0814c5c0b19ade497851070c640773304939a6c0fd5f5fb43da0696d05b7" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6a647510471d372f2e6c2e6b7219e44d8c574d24fdc11c610a61455782f18c3" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "synstructure", ] [[package]] name = "zerovec" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff4439ae91fb5c72b8abc12f3f2dbf51bd27e6eadb9f8a5bc8898dddb0e27ea" +checksum = "bb2cc8827d6c0994478a15c53f374f46fbd41bea663d809b14744bc42e6b109c" dependencies = [ "yoke", "zerofrom", @@ -6563,11 +6692,11 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4e5997cbf58990550ef1f0e5124a05e47e1ebd33a84af25739be6031a62c20" +checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] diff --git a/RELEASES.md b/RELEASES.md index 3080f03c721..c1311ab14c5 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,131 @@ +Version 1.79.0 (2024-06-13) +========================== + +<a id="1.79.0-Language"></a> + +Language +-------- +- [Stabilize inline `const {}` expressions.](https://github.com/rust-lang/rust/pull/104087/) +- [Prevent opaque types being instantiated twice with different regions within the same function.](https://github.com/rust-lang/rust/pull/116935/) +- [Stabilize WebAssembly target features that are in phase 4 and 5.](https://github.com/rust-lang/rust/pull/117457/) +- [Add the `redundant_lifetimes` lint to detect lifetimes which are semantically redundant.](https://github.com/rust-lang/rust/pull/118391/) +- [Stabilize the `unnameable_types` lint for public types that can't be named.](https://github.com/rust-lang/rust/pull/120144/) +- [Enable debuginfo in macros, and stabilize `-C collapse-macro-debuginfo` and `#[collapse_debuginfo]`.](https://github.com/rust-lang/rust/pull/120845/) +- [Propagate temporary lifetime extension into `if` and `match` expressions.](https://github.com/rust-lang/rust/pull/121346/) +- [Restrict promotion of `const fn` calls.](https://github.com/rust-lang/rust/pull/121557/) +- [Warn against refining impls of crate-private traits with `refining_impl_trait` lint.](https://github.com/rust-lang/rust/pull/121720/) +- [Stabilize associated type bounds (RFC 2289).](https://github.com/rust-lang/rust/pull/122055/) +- [Stabilize importing `main` from other modules or crates.](https://github.com/rust-lang/rust/pull/122060/) +- [Check return types of function types for well-formedness](https://github.com/rust-lang/rust/pull/115538) +- [Rework `impl Trait` lifetime inference](https://github.com/rust-lang/rust/pull/116891/) +- [Change inductive trait solver cycles to be ambiguous](https://github.com/rust-lang/rust/pull/122791) + +<a id="1.79.0-Compiler"></a> + +Compiler +-------- +- [Define `-C strip` to only affect binaries, not artifacts like `.pdb`.](https://github.com/rust-lang/rust/pull/115120/) +- [Stabilize `-Crelro-level` for controlling runtime link hardening.](https://github.com/rust-lang/rust/pull/121694/) +- [Stabilize checking of `cfg` names and values at compile-time with `--check-cfg`.](https://github.com/rust-lang/rust/pull/123501/) + *Note that this only stabilizes the compiler part, the Cargo part is still unstable in this release.* +- [Add `aarch64-apple-visionos` and `aarch64-apple-visionos-sim` tier 3 targets.](https://github.com/rust-lang/rust/pull/121419/) +- [Add `riscv32ima-unknown-none-elf` tier 3 target.](https://github.com/rust-lang/rust/pull/122696/) +- [Promote several Windows targets to tier 2](https://github.com/rust-lang/rust/pull/121712): `aarch64-pc-windows-gnullvm`, `i686-pc-windows-gnullvm`, and `x86_64-pc-windows-gnullvm`. + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + +<a id="1.79.0-Libraries"></a> + +Libraries +--------- + +- [Implement `FromIterator` for `(impl Default + Extend, impl Default + Extend)`.](https://github.com/rust-lang/rust/pull/107462/) +- [Implement `{Div,Rem}Assign<NonZero<X>>` on `X`.](https://github.com/rust-lang/rust/pull/121952/) +- [Document overrides of `clone_from()` in core/std.](https://github.com/rust-lang/rust/pull/122201/) +- [Link MSVC default lib in core.](https://github.com/rust-lang/rust/pull/122268/) +- [Caution against using `transmute` between pointers and integers.](https://github.com/rust-lang/rust/pull/122379/) +- [Enable frame pointers for the standard library.](https://github.com/rust-lang/rust/pull/122646/) + +<a id="1.79.0-Stabilized-APIs"></a> + +Stabilized APIs +--------------- + +- [`{integer}::unchecked_add`](https://doc.rust-lang.org/stable/core/primitive.i32.html#method.unchecked_add) +- [`{integer}::unchecked_mul`](https://doc.rust-lang.org/stable/core/primitive.i32.html#method.unchecked_mul) +- [`{integer}::unchecked_sub`](https://doc.rust-lang.org/stable/core/primitive.i32.html#method.unchecked_sub) +- [`<[T]>::split_at_unchecked`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_at_unchecked) +- [`<[T]>::split_at_mut_unchecked`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_at_mut_unchecked) +- [`<[u8]>::utf8_chunks`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.utf8_chunks) +- [`str::Utf8Chunks`](https://doc.rust-lang.org/stable/core/str/struct.Utf8Chunks.html) +- [`str::Utf8Chunk`](https://doc.rust-lang.org/stable/core/str/struct.Utf8Chunk.html) +- [`<*const T>::is_aligned`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.is_aligned) +- [`<*mut T>::is_aligned`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.is_aligned-1) +- [`NonNull::is_aligned`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.is_aligned) +- [`<*const [T]>::len`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.len) +- [`<*mut [T]>::len`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.len-1) +- [`<*const [T]>::is_empty`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.is_empty) +- [`<*mut [T]>::is_empty`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.is_empty-1) +- [`NonNull::<[T]>::is_empty`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.is_empty) +- [`CStr::count_bytes`](https://doc.rust-lang.org/stable/core/ffi/c_str/struct.CStr.html#method.count_bytes) +- [`io::Error::downcast`](https://doc.rust-lang.org/stable/std/io/struct.Error.html#method.downcast) +- [`num::NonZero<T>`](https://doc.rust-lang.org/stable/core/num/struct.NonZero.html) +- [`path::absolute`](https://doc.rust-lang.org/stable/std/path/fn.absolute.html) +- [`proc_macro::Literal::byte_character`](https://doc.rust-lang.org/stable/proc_macro/struct.Literal.html#method.byte_character) +- [`proc_macro::Literal::c_string`](https://doc.rust-lang.org/stable/proc_macro/struct.Literal.html#method.c_string) + +These APIs are now stable in const contexts: + +- [`Atomic*::into_inner`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicUsize.html#method.into_inner) +- [`io::Cursor::new`](https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#method.new) +- [`io::Cursor::get_ref`](https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#method.get_ref) +- [`io::Cursor::position`](https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#method.position) +- [`io::empty`](https://doc.rust-lang.org/stable/std/io/fn.empty.html) +- [`io::repeat`](https://doc.rust-lang.org/stable/std/io/fn.repeat.html) +- [`io::sink`](https://doc.rust-lang.org/stable/std/io/fn.sink.html) +- [`panic::Location::caller`](https://doc.rust-lang.org/stable/std/panic/struct.Location.html#method.caller) +- [`panic::Location::file`](https://doc.rust-lang.org/stable/std/panic/struct.Location.html#method.file) +- [`panic::Location::line`](https://doc.rust-lang.org/stable/std/panic/struct.Location.html#method.line) +- [`panic::Location::column`](https://doc.rust-lang.org/stable/std/panic/struct.Location.html#method.column) + +<a id="1.79.0-Cargo"></a> + +Cargo +----- + +- [Prevent dashes in `lib.name`, always normalizing to `_`.](https://github.com/rust-lang/cargo/pull/12783/) +- [Stabilize MSRV-aware version requirement selection in `cargo add`.](https://github.com/rust-lang/cargo/pull/13608/) +- [Switch to using `gitoxide` by default for listing files.](https://github.com/rust-lang/cargo/pull/13696/) +- [Error on `[project]` in Edition 2024; `cargo fix --edition` will change it to `[package]`.](https://github.com/rust-lang/cargo/pull/13747/) + +<a id="1.79.0-Rustdoc"></a> + +Rustdoc +----- + +- [Always display stability version even if it's the same as the containing item.](https://github.com/rust-lang/rust/pull/118441/) +- [Show a single search result for items with multiple paths.](https://github.com/rust-lang/rust/pull/119912/) +- [Support typing `/` in docs to begin a search.](https://github.com/rust-lang/rust/pull/123355/) + +<a id="1.79.0-Misc"></a> + +Misc +---- + +<a id="1.79.0-Compatibility-Notes"></a> + +Compatibility Notes +------------------- + +- [Update the minimum external LLVM to 17.](https://github.com/rust-lang/rust/pull/122649/) +- [`RustcEncodable` and `RustcDecodable` are soft-destabilized, to be removed + from the prelude in next edition.](https://github.com/rust-lang/rust/pull/116016/) +- [The `wasm_c_abi` future-incompatibility lint will warn about use of the + non-spec-compliant C ABI.](https://github.com/rust-lang/rust/pull/117918/) + Use `wasm-bindgen v0.2.88` to generate forward-compatible bindings. +- [Check return types of function types for well-formedness](https://github.com/rust-lang/rust/pull/115538) + Version 1.78.0 (2024-05-02) ========================== diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 7a45d909d07..9cb193b4a67 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -488,6 +488,7 @@ pub struct Crate { /// E.g., `#[test]`, `#[derive(..)]`, `#[rustfmt::skip]` or `#[feature = "foo"]`. #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub struct MetaItem { + pub unsafety: Safety, pub path: Path, pub kind: MetaItemKind, pub span: Span, @@ -1392,7 +1393,7 @@ pub enum ExprKind { /// An array (e.g, `[a, b, c, d]`). Array(ThinVec<P<Expr>>), /// Allow anonymous constants from an inline `const` block - ConstBlock(P<Expr>), + ConstBlock(AnonConst), /// A function call /// /// The first field resolves to the function itself, @@ -2501,6 +2502,8 @@ pub enum IsAuto { pub enum Safety { /// `unsafe` an item is explicitly marked as `unsafe`. Unsafe(Span), + /// `safe` an item is explicitly marked as `safe`. + Safe(Span), /// Default means no value was provided, it will take a default value given the context in /// which is used. Default, @@ -2821,7 +2824,12 @@ pub struct NormalAttr { impl NormalAttr { pub fn from_ident(ident: Ident) -> Self { Self { - item: AttrItem { path: Path::from_ident(ident), args: AttrArgs::Empty, tokens: None }, + item: AttrItem { + unsafety: Safety::Default, + path: Path::from_ident(ident), + args: AttrArgs::Empty, + tokens: None, + }, tokens: None, } } @@ -2829,6 +2837,7 @@ impl NormalAttr { #[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)] pub struct AttrItem { + pub unsafety: Safety, pub path: Path, pub args: AttrArgs, // Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`. @@ -3162,6 +3171,7 @@ pub struct DelegationMac { #[derive(Clone, Encodable, Decodable, Debug)] pub struct StaticItem { pub ty: P<Ty>, + pub safety: Safety, pub mutability: Mutability, pub expr: Option<P<Expr>>, } @@ -3171,6 +3181,7 @@ pub struct StaticItem { #[derive(Clone, Encodable, Decodable, Debug)] pub struct StaticForeignItem { pub ty: P<Ty>, + pub safety: Safety, pub mutability: Mutability, pub expr: Option<P<Expr>>, } @@ -3179,6 +3190,7 @@ impl From<StaticItem> for StaticForeignItem { fn from(static_item: StaticItem) -> StaticForeignItem { StaticForeignItem { ty: static_item.ty, + safety: static_item.safety, mutability: static_item.mutability, expr: static_item.expr, } @@ -3189,6 +3201,7 @@ impl From<StaticForeignItem> for StaticItem { fn from(static_item: StaticForeignItem) -> StaticItem { StaticItem { ty: static_item.ty, + safety: static_item.safety, mutability: static_item.mutability, expr: static_item.expr, } diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index d5c9fc960c8..676a2377c3b 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -1,6 +1,8 @@ //! Functions dealing with attributes and meta items. -use crate::ast::{AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute}; +use crate::ast::{ + AttrArgs, AttrArgsEq, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, Safety, +}; use crate::ast::{DelimArgs, Expr, ExprKind, LitKind, MetaItemLit}; use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem, NormalAttr}; use crate::ast::{Path, PathSegment, DUMMY_NODE_ID}; @@ -238,7 +240,12 @@ impl AttrItem { } pub fn meta(&self, span: Span) -> Option<MetaItem> { - Some(MetaItem { path: self.path.clone(), kind: self.meta_kind()?, span }) + Some(MetaItem { + unsafety: Safety::Default, + path: self.path.clone(), + kind: self.meta_kind()?, + span, + }) } pub fn meta_kind(&self) -> Option<MetaItemKind> { @@ -371,7 +378,10 @@ impl MetaItem { _ => path.span.hi(), }; let span = path.span.with_hi(hi); - Some(MetaItem { path, kind, span }) + // FIXME: This parses `unsafe()` not as unsafe attribute syntax in `MetaItem`, + // but as a parenthesized list. This (and likely `MetaItem`) should be changed in + // such a way that builtin macros don't accept extraneous `unsafe()`. + Some(MetaItem { unsafety: Safety::Default, path, kind, span }) } } @@ -555,11 +565,12 @@ pub fn mk_doc_comment( pub fn mk_attr( g: &AttrIdGenerator, style: AttrStyle, + unsafety: Safety, path: Path, args: AttrArgs, span: Span, ) -> Attribute { - mk_attr_from_item(g, AttrItem { path, args, tokens: None }, None, style, span) + mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span) } pub fn mk_attr_from_item( @@ -577,15 +588,22 @@ pub fn mk_attr_from_item( } } -pub fn mk_attr_word(g: &AttrIdGenerator, style: AttrStyle, name: Symbol, span: Span) -> Attribute { +pub fn mk_attr_word( + g: &AttrIdGenerator, + style: AttrStyle, + unsafety: Safety, + name: Symbol, + span: Span, +) -> Attribute { let path = Path::from_ident(Ident::new(name, span)); let args = AttrArgs::Empty; - mk_attr(g, style, path, args, span) + mk_attr(g, style, unsafety, path, args, span) } pub fn mk_attr_nested_word( g: &AttrIdGenerator, style: AttrStyle, + unsafety: Safety, outer: Symbol, inner: Symbol, span: Span, @@ -601,12 +619,13 @@ pub fn mk_attr_nested_word( delim: Delimiter::Parenthesis, tokens: inner_tokens, }); - mk_attr(g, style, path, attr_args, span) + mk_attr(g, style, unsafety, path, attr_args, span) } pub fn mk_attr_name_value_str( g: &AttrIdGenerator, style: AttrStyle, + unsafety: Safety, name: Symbol, val: Symbol, span: Span, @@ -621,7 +640,7 @@ pub fn mk_attr_name_value_str( }); let path = Path::from_ident(Ident::new(name, span)); let args = AttrArgs::Eq(span, AttrArgsEq::Ast(expr)); - mk_attr(g, style, path, args, span) + mk_attr(g, style, unsafety, path, args, span) } pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 5c581c270e4..cc33ce2cb56 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -647,8 +647,10 @@ fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) { let Attribute { kind, id: _, style: _, span } = attr; match kind { AttrKind::Normal(normal) => { - let NormalAttr { item: AttrItem { path, args, tokens }, tokens: attr_tokens } = - &mut **normal; + let NormalAttr { + item: AttrItem { unsafety: _, path, args, tokens }, + tokens: attr_tokens, + } = &mut **normal; vis.visit_path(path); visit_attr_args(args, vis); visit_lazy_tts(tokens, vis); @@ -678,7 +680,7 @@ fn noop_visit_meta_list_item<T: MutVisitor>(li: &mut NestedMetaItem, vis: &mut T } fn noop_visit_meta_item<T: MutVisitor>(mi: &mut MetaItem, vis: &mut T) { - let MetaItem { path: _, kind, span } = mi; + let MetaItem { unsafety: _, path: _, kind, span } = mi; match kind { MetaItemKind::Word => {} MetaItemKind::List(mis) => visit_thin_vec(mis, |mi| vis.visit_meta_list_item(mi)), @@ -840,7 +842,7 @@ fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) { token::NtTy(ty) => vis.visit_ty(ty), token::NtLiteral(expr) => vis.visit_expr(expr), token::NtMeta(item) => { - let AttrItem { path, args, tokens } = item.deref_mut(); + let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut(); vis.visit_path(path); visit_attr_args(args, vis); visit_lazy_tts(tokens, vis); @@ -862,6 +864,7 @@ fn visit_defaultness<T: MutVisitor>(defaultness: &mut Defaultness, vis: &mut T) fn visit_safety<T: MutVisitor>(safety: &mut Safety, vis: &mut T) { match safety { Safety::Unsafe(span) => vis.visit_span(span), + Safety::Safe(span) => vis.visit_span(span), Safety::Default => {} } } @@ -1079,7 +1082,7 @@ impl NoopVisitItemKind for ItemKind { match self { ItemKind::ExternCrate(_orig_name) => {} ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), - ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { vis.visit_ty(ty); visit_opt(expr, |expr| vis.visit_expr(expr)); } @@ -1289,7 +1292,12 @@ pub fn noop_flat_map_item<K: NoopVisitItemKind>( impl NoopVisitItemKind for ForeignItemKind { fn noop_visit(&mut self, visitor: &mut impl MutVisitor) { match self { - ForeignItemKind::Static(box StaticForeignItem { ty, mutability: _, expr }) => { + ForeignItemKind::Static(box StaticForeignItem { + ty, + mutability: _, + expr, + safety: _, + }) => { visitor.visit_ty(ty); visit_opt(expr, |expr| visitor.visit_expr(expr)); } @@ -1411,7 +1419,7 @@ pub fn noop_visit_expr<T: MutVisitor>( match kind { ExprKind::Array(exprs) => visit_thin_exprs(exprs, vis), ExprKind::ConstBlock(anon_const) => { - vis.visit_expr(anon_const); + vis.visit_anon_const(anon_const); } ExprKind::Repeat(expr, count) => { vis.visit_expr(expr); diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 099a6096d0b..109c401bb6a 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -210,6 +210,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: IdentIsRaw) -> boo kw::Unsafe, kw::While, kw::Yield, + kw::Safe, kw::Static, ] .contains(&name) @@ -577,6 +578,7 @@ impl Token { kw::Impl, kw::Unsafe, kw::Const, + kw::Safe, kw::Static, kw::Union, kw::Macro, diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index b2f3b27c77e..fa97c8db326 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -334,7 +334,7 @@ impl WalkItemKind for ItemKind { match self { ItemKind::ExternCrate(_) => {} ItemKind::Use(use_tree) => try_visit!(visitor.visit_use_tree(use_tree, item.id, false)), - ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); } @@ -658,7 +658,12 @@ impl WalkItemKind for ForeignItemKind { ) -> V::Result { let &Item { id, span, ident, ref vis, .. } = item; match self { - ForeignItemKind::Static(box StaticForeignItem { ty, mutability: _, expr }) => { + ForeignItemKind::Static(box StaticForeignItem { + ty, + mutability: _, + expr, + safety: _, + }) => { try_visit!(visitor.visit_ty(ty)); visit_opt!(visitor, visit_expr, expr); } @@ -954,7 +959,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V ExprKind::Array(subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } - ExprKind::ConstBlock(anon_const) => try_visit!(visitor.visit_expr(anon_const)), + ExprKind::ConstBlock(anon_const) => try_visit!(visitor.visit_anon_const(anon_const)), ExprKind::Repeat(element, count) => { try_visit!(visitor.visit_expr(element)); try_visit!(visitor.visit_anon_const(count)); diff --git a/compiler/rustc_ast_ir/Cargo.toml b/compiler/rustc_ast_ir/Cargo.toml index e761b7adad3..a78c91e0615 100644 --- a/compiler/rustc_ast_ir/Cargo.toml +++ b/compiler/rustc_ast_ir/Cargo.toml @@ -9,7 +9,6 @@ rustc_data_structures = { path = "../rustc_data_structures", optional = true } 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" } # tidy-alphabetical-end [features] diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 27f8a6eae02..d9dd0b3bca5 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -67,7 +67,9 @@ impl<'hir> LoweringContext<'_, 'hir> { return false; }; if let Some(local_sig_id) = sig_id.as_local() { - self.resolver.delegation_fn_sigs[&local_sig_id].has_self + // The value may be missing due to recursive delegation. + // Error will be emmited later during HIR ty lowering. + self.resolver.delegation_fn_sigs.get(&local_sig_id).map_or(false, |sig| sig.has_self) } else { match self.tcx.def_kind(sig_id) { DefKind::Fn => false, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index eb206a09be3..77f95869e9d 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -75,8 +75,12 @@ impl<'hir> LoweringContext<'_, 'hir> { let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), ExprKind::ConstBlock(c) => { - self.has_inline_consts = true; - hir::ExprKind::ConstBlock(self.lower_expr(c)) + let c = self.with_new_scopes(c.value.span, |this| hir::ConstBlock { + def_id: this.local_def_id(c.id), + hir_id: this.lower_node_id(c.id), + body: this.lower_const_body(c.value.span, Some(&c.value)), + }); + hir::ExprKind::ConstBlock(c) } ExprKind::Repeat(expr, count) => { let expr = self.lower_expr(expr); @@ -1801,6 +1805,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let attr = attr::mk_attr_nested_word( &self.tcx.sess.psess.attr_id_generator, AttrStyle::Outer, + Safety::Default, sym::allow, sym::unreachable_code, self.lower_span(span), diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 741a44eb0c5..44f37b5533a 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -236,6 +236,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { }); } + fn visit_inline_const(&mut self, constant: &'hir ConstBlock) { + self.insert(DUMMY_SP, constant.hir_id, Node::ConstBlock(constant)); + + self.with_parent(constant.hir_id, |this| { + intravisit::walk_inline_const(this, constant); + }); + } + fn visit_expr(&mut self, expr: &'hir Expr<'hir>) { self.insert(expr.span, expr.hir_id, Node::Expr(expr)); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a15449409df..8c963e9f890 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -181,7 +181,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_use_tree(use_tree, &prefix, id, vis_span, ident, attrs) } - ItemKind::Static(box ast::StaticItem { ty: t, mutability: m, expr: e }) => { + ItemKind::Static(box ast::StaticItem { ty: t, safety: _, mutability: m, expr: e }) => { let (ty, body_id) = self.lower_const_item(t, span, e.as_deref(), ImplTraitPosition::StaticTy); hir::ItemKind::Static(ty, *m, body_id) @@ -388,7 +388,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(*s)), }; hir::ItemKind::Impl(self.arena.alloc(hir::Impl { - safety: self.lower_safety(*safety), + safety: self.lower_safety(*safety, hir::Safety::Safe), polarity, defaultness, defaultness_span, @@ -418,7 +418,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let items = this.arena.alloc_from_iter( items.iter().map(|item| this.lower_trait_item_ref(item)), ); - let safety = this.lower_safety(*safety); + let safety = this.lower_safety(*safety, hir::Safety::Safe); (safety, items, bounds) }, ); @@ -660,13 +660,21 @@ impl<'hir> LoweringContext<'_, 'hir> { this.lower_fn_params_to_names(fdec), ) }); + let safety = self.lower_safety(sig.header.safety, hir::Safety::Unsafe); - hir::ForeignItemKind::Fn(fn_dec, fn_args, generics) + hir::ForeignItemKind::Fn(fn_dec, fn_args, generics, safety) } - ForeignItemKind::Static(box StaticForeignItem { ty, mutability, expr: _ }) => { + ForeignItemKind::Static(box StaticForeignItem { + ty, + mutability, + expr: _, + safety, + }) => { let ty = self .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); - hir::ForeignItemKind::Static(ty, *mutability) + let safety = self.lower_safety(*safety, hir::Safety::Unsafe); + + hir::ForeignItemKind::Static(ty, *mutability, safety) } ForeignItemKind::TyAlias(..) => hir::ForeignItemKind::Type, ForeignItemKind::MacCall(_) => panic!("macro shouldn't exist here"), @@ -1360,7 +1368,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::IsAsync::NotAsync }; hir::FnHeader { - safety: self.lower_safety(h.safety), + safety: self.lower_safety(h.safety, hir::Safety::Safe), asyncness: asyncness, constness: self.lower_constness(h.constness), abi: self.lower_extern(h.ext), @@ -1410,10 +1418,11 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - pub(super) fn lower_safety(&mut self, s: Safety) -> hir::Safety { + pub(super) fn lower_safety(&mut self, s: Safety, default: hir::Safety) -> hir::Safety { match s { Safety::Unsafe(_) => hir::Safety::Unsafe, - Safety::Default => hir::Safety::Safe, + Safety::Default => default, + Safety::Safe(_) => hir::Safety::Safe, } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 5a80fa803f8..1c6b5b9af19 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -96,8 +96,6 @@ struct LoweringContext<'a, 'hir> { /// Bodies inside the owner being lowered. bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>, - /// Whether there were inline consts that typeck will split out into bodies - has_inline_consts: bool, /// Attributes inside the owner being lowered. attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>, /// Collect items that were created by lowering the current owner. @@ -160,7 +158,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { item_local_id_counter: hir::ItemLocalId::ZERO, node_id_to_local_id: Default::default(), trait_map: Default::default(), - has_inline_consts: false, // Lowering state. catch_scope: None, @@ -570,7 +567,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let current_attrs = std::mem::take(&mut self.attrs); let current_bodies = std::mem::take(&mut self.bodies); - let current_has_inline_consts = std::mem::take(&mut self.has_inline_consts); let current_node_ids = std::mem::take(&mut self.node_id_to_local_id); let current_trait_map = std::mem::take(&mut self.trait_map); let current_owner = @@ -597,7 +593,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.attrs = current_attrs; self.bodies = current_bodies; - self.has_inline_consts = current_has_inline_consts; self.node_id_to_local_id = current_node_ids; self.trait_map = current_trait_map; self.current_hir_id_owner = current_owner; @@ -634,7 +629,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let attrs = std::mem::take(&mut self.attrs); let mut bodies = std::mem::take(&mut self.bodies); let trait_map = std::mem::take(&mut self.trait_map); - let has_inline_consts = std::mem::take(&mut self.has_inline_consts); #[cfg(debug_assertions)] for (id, attrs) in attrs.iter() { @@ -652,7 +646,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.tcx.hash_owner_nodes(node, &bodies, &attrs); let num_nodes = self.item_local_id_counter.as_usize(); let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes); - let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies, has_inline_consts }; + let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies }; let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash }; self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map }) @@ -911,6 +905,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let kind = match attr.kind { AttrKind::Normal(ref normal) => AttrKind::Normal(P(NormalAttr { item: AttrItem { + unsafety: normal.item.unsafety, path: normal.item.path.clone(), args: self.lower_attr_args(&normal.item.args), tokens: None, @@ -1321,7 +1316,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params); hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy { generic_params, - safety: self.lower_safety(f.safety), + safety: self.lower_safety(f.safety, hir::Safety::Safe), abi: self.lower_extern(f.ext), decl: self.lower_fn_decl(&f.decl, t.id, t.span, FnDeclKind::Pointer, None), param_names: self.lower_fn_params_to_names(&f.decl), diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 3a4c95b250c..9a8689e27c0 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -67,6 +67,9 @@ ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have quali .label = in this `extern` block .suggestion = remove this qualifier +ast_passes_extern_invalid_safety = items in unadorned `extern` blocks cannot have safety qualifiers + .suggestion = add unsafe to this `extern` block + ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers .label = in this `extern` block .note = this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information @@ -174,6 +177,8 @@ ast_passes_match_arm_with_no_body = `match` arm with no body .suggestion = add a body after the pattern +ast_passes_missing_unsafe_on_extern = extern blocks must be unsafe + ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name .help = consider using the `#[path]` attribute to specify filesystem path diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 435b0b6a956..0fbb288cc96 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -15,7 +15,8 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_feature::Features; use rustc_parse::validate_attr; use rustc_session::lint::builtin::{ - DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY, + DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN, + PATTERNS_IN_FNS_WITHOUT_BODY, }; use rustc_session::lint::{BuiltinLintDiag, LintBuffer}; use rustc_session::Session; @@ -86,6 +87,9 @@ struct AstValidator<'a> { /// or `Foo::Bar<impl Trait>` is_impl_trait_banned: bool, + /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe. + extern_mod_safety: Option<Safety>, + lint_buffer: &'a mut LintBuffer, } @@ -116,6 +120,12 @@ impl<'a> AstValidator<'a> { self.outer_trait_or_trait_impl = old; } + fn with_in_extern_mod(&mut self, extern_mod_safety: Safety, f: impl FnOnce(&mut Self)) { + let old = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety)); + f(self); + self.extern_mod_safety = old; + } + fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) { let old = mem::replace(&mut self.is_impl_trait_banned, true); f(self); @@ -429,6 +439,18 @@ impl<'a> AstValidator<'a> { } } + fn check_foreign_item_safety(&self, item_span: Span, safety: Safety) { + if matches!(safety, Safety::Unsafe(_) | Safety::Safe(_)) + && (self.extern_mod_safety == Some(Safety::Default) + || !self.features.unsafe_extern_blocks) + { + self.dcx().emit_err(errors::InvalidSafetyOnExtern { + item_span, + block: self.current_extern_span(), + }); + } + } + fn check_defaultness(&self, span: Span, defaultness: Defaultness) { if let Defaultness::Default(def_span) = defaultness { let span = self.session.source_map().guess_head_span(span); @@ -518,7 +540,7 @@ impl<'a> AstValidator<'a> { fn check_foreign_fn_headerless( &self, // Deconstruct to ensure exhaustiveness - FnHeader { safety, coroutine_kind, constness, ext }: FnHeader, + FnHeader { safety: _, coroutine_kind, constness, ext }: FnHeader, ) { let report_err = |span| { self.dcx().emit_err(errors::FnQualifierInExtern { @@ -526,10 +548,6 @@ impl<'a> AstValidator<'a> { block: self.current_extern_span(), }); }; - match safety { - Safety::Unsafe(span) => report_err(span), - Safety::Default => (), - } match coroutine_kind { Some(knd) => report_err(knd.span()), None => (), @@ -1017,19 +1035,39 @@ impl<'a> Visitor<'a> for AstValidator<'a> { return; // Avoid visiting again. } ItemKind::ForeignMod(ForeignMod { abi, safety, .. }) => { - let old_item = mem::replace(&mut self.extern_mod, Some(item)); - self.visibility_not_permitted( - &item.vis, - errors::VisibilityNotPermittedNote::IndividualForeignItems, - ); - if let &Safety::Unsafe(span) = safety { - self.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" }); - } - if abi.is_none() { - self.maybe_lint_missing_abi(item.span, item.id); - } - visit::walk_item(self, item); - self.extern_mod = old_item; + self.with_in_extern_mod(*safety, |this| { + let old_item = mem::replace(&mut this.extern_mod, Some(item)); + this.visibility_not_permitted( + &item.vis, + errors::VisibilityNotPermittedNote::IndividualForeignItems, + ); + + if this.features.unsafe_extern_blocks { + if &Safety::Default == safety { + if item.span.at_least_rust_2024() { + this.dcx() + .emit_err(errors::MissingUnsafeOnExtern { span: item.span }); + } else { + this.lint_buffer.buffer_lint( + MISSING_UNSAFE_ON_EXTERN, + item.id, + item.span, + BuiltinLintDiag::MissingUnsafeOnExtern { + suggestion: item.span.shrink_to_lo(), + }, + ); + } + } + } else if let &Safety::Unsafe(span) = safety { + this.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" }); + } + + if abi.is_none() { + this.maybe_lint_missing_abi(item.span, item.id); + } + visit::walk_item(this, item); + this.extern_mod = old_item; + }); return; // Avoid visiting again. } ItemKind::Enum(def, _) => { @@ -1161,6 +1199,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { match &fi.kind { ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => { + self.check_foreign_item_safety(fi.span, sig.header.safety); self.check_defaultness(fi.span, *defaultness); self.check_foreign_fn_bodyless(fi.ident, body.as_deref()); self.check_foreign_fn_headerless(sig.header); @@ -1180,7 +1219,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_foreign_ty_genericless(generics, where_clauses); self.check_foreign_item_ascii_only(fi.ident); } - ForeignItemKind::Static(box StaticForeignItem { ty: _, mutability: _, expr }) => { + ForeignItemKind::Static(box StaticForeignItem { expr, safety, .. }) => { + self.check_foreign_item_safety(fi.span, *safety); self.check_foreign_kind_bodyless(fi.ident, "static", expr.as_ref().map(|b| b.span)); self.check_foreign_item_ascii_only(fi.ident); } @@ -1736,6 +1776,7 @@ pub fn check_crate( outer_impl_trait: None, disallow_tilde_const: Some(DisallowTildeConstContext::Item), is_impl_trait_banned: false, + extern_mod_safety: None, lint_buffer: lints, }; visit::walk_crate(&mut validator, krate); diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index c07fbe5b016..260c182bd9e 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -217,6 +217,15 @@ pub enum ExternBlockSuggestion { } #[derive(Diagnostic)] +#[diag(ast_passes_extern_invalid_safety)] +pub struct InvalidSafetyOnExtern { + #[primary_span] + pub item_span: Span, + #[suggestion(code = "", applicability = "maybe-incorrect")] + pub block: Span, +} + +#[derive(Diagnostic)] #[diag(ast_passes_bound_in_context)] pub struct BoundInContext<'a> { #[primary_span] @@ -486,6 +495,13 @@ pub struct UnsafeItem { } #[derive(Diagnostic)] +#[diag(ast_passes_missing_unsafe_on_extern)] +pub struct MissingUnsafeOnExtern { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(ast_passes_fieldless_union)] pub struct FieldlessUnion { #[primary_span] diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index a9dca9b6a29..764d942836c 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -561,6 +561,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(mut_ref, "mutable by-reference bindings are experimental"); gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental"); gate_all!(global_registration, "global registration is experimental"); + gate_all!(unsafe_attributes, "`#[unsafe()]` markers for attributes are experimental"); if !visitor.features.never_patterns { if let Some(spans) = spans.get(&sym::never_patterns) { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 4c29ca0ca46..f32b63a39f0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -16,7 +16,7 @@ use rustc_ast::token::{self, BinOpToken, CommentKind, Delimiter, Nonterminal, To use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree}; use rustc_ast::util::classify; use rustc_ast::util::comments::{Comment, CommentStyle}; -use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind}; +use rustc_ast::{self as ast, AttrArgs, AttrArgsEq, BlockCheckMode, PatKind, Safety}; use rustc_ast::{attr, BindingMode, ByRef, DelimArgs, RangeEnd, RangeSyntax, Term}; use rustc_ast::{GenericArg, GenericBound, SelfKind}; use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass}; @@ -249,6 +249,7 @@ pub fn print_crate<'a>( let fake_attr = attr::mk_attr_nested_word( g, ast::AttrStyle::Inner, + Safety::Default, sym::feature, sym::prelude_import, DUMMY_SP, @@ -259,7 +260,13 @@ pub fn print_crate<'a>( // root, so this is not needed, and actually breaks things. if edition.is_rust_2015() { // `#![no_std]` - let fake_attr = attr::mk_attr_word(g, ast::AttrStyle::Inner, sym::no_std, DUMMY_SP); + let fake_attr = attr::mk_attr_word( + g, + ast::AttrStyle::Inner, + Safety::Default, + sym::no_std, + DUMMY_SP, + ); s.print_attribute(&fake_attr); } } @@ -1973,6 +1980,7 @@ impl<'a> State<'a> { fn print_safety(&mut self, s: ast::Safety) { match s { ast::Safety::Default => {} + ast::Safety::Safe(_) => self.word_nbsp("safe"), ast::Safety::Unsafe(_) => self.word_nbsp("unsafe"), } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 993ccc5b956..1e117c46b6e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -380,9 +380,8 @@ impl<'a> State<'a> { ast::ExprKind::Array(exprs) => { self.print_expr_vec(exprs); } - ast::ExprKind::ConstBlock(expr) => { - self.word_space("const"); - self.print_expr(expr, FixupContext::default()); + ast::ExprKind::ConstBlock(anon_const) => { + self.print_expr_anon_const(anon_const, attrs); } ast::ExprKind::Repeat(element, count) => { self.print_expr_repeat(element, count); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 59d9b0c1a8e..474741fb067 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -31,7 +31,13 @@ impl<'a> State<'a> { ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => { self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs); } - ast::ForeignItemKind::Static(box ast::StaticForeignItem { ty, mutability, expr }) => { + ast::ForeignItemKind::Static(box ast::StaticForeignItem { + ty, + mutability, + expr, + safety, + }) => { + self.print_safety(*safety); self.print_item_const( ident, Some(*mutability), @@ -165,7 +171,8 @@ impl<'a> State<'a> { self.print_use_tree(tree); self.word(";"); } - ast::ItemKind::Static(box StaticItem { ty, mutability: mutbl, expr: body }) => { + ast::ItemKind::Static(box StaticItem { ty, safety, mutability: mutbl, expr: body }) => { + self.print_safety(*safety); self.print_item_const( item.ident, Some(*mutbl), diff --git a/compiler/rustc_baked_icu_data/Cargo.toml b/compiler/rustc_baked_icu_data/Cargo.toml index 48af4e6f600..e6cfb4887c9 100644 --- a/compiler/rustc_baked_icu_data/Cargo.toml +++ b/compiler/rustc_baked_icu_data/Cargo.toml @@ -9,7 +9,6 @@ icu_list = "1.2" icu_locid = "1.2" icu_locid_transform = "1.3.2" icu_provider = "1.2" -icu_provider_adapters = "1.2" zerovec = "0.10.0" # tidy-alphabetical-end diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index ff11e4db121..97408fa20d7 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -1,7 +1,7 @@ use rustc_data_structures::graph::scc::Sccs; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::{RegionVid, VarianceDiagInfo}; +use rustc_middle::ty::{RegionVid, TyCtxt, VarianceDiagInfo}; use rustc_span::Span; use std::fmt; use std::ops::Index; @@ -97,7 +97,7 @@ pub struct OutlivesConstraint<'tcx> { pub category: ConstraintCategory<'tcx>, /// Variance diagnostic information - pub variance_info: VarianceDiagInfo<'tcx>, + pub variance_info: VarianceDiagInfo<TyCtxt<'tcx>>, /// If this constraint is promoted from closure requirements. pub from_closure: bool, diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index cde7ac94e35..821a9036654 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1347,7 +1347,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return; }; // Try to find predicates on *generic params* that would allow copying `ty` - let ocx = ObligationCtxt::new(self.infcx); + let ocx = ObligationCtxt::new_with_diagnostics(self.infcx); let cause = ObligationCause::misc(span, self.mir_def_id()); ocx.register_bound(cause, self.param_env, ty, def_id); diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 88172c62a3b..1eb67ea367c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -11,7 +11,7 @@ use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::CoroutineKind; use rustc_index::IndexSlice; use rustc_infer::infer::BoundRegionConversionTime; -use rustc_infer::traits::{FulfillmentErrorCode, SelectionError}; +use rustc_infer::traits::SelectionError; use rustc_middle::bug; use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::{ @@ -29,7 +29,9 @@ use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions; +use rustc_trait_selection::traits::{ + type_known_to_meet_bound_modulo_regions, FulfillmentErrorCode, +}; use crate::fluent_generated as fluent; diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 78798545c26..df1a1411cf5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -6,7 +6,6 @@ use hir::{ExprKind, Param}; use rustc_errors::{Applicability, Diag}; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, BindingMode, ByRef, Node}; -use rustc_infer::traits; use rustc_middle::bug; use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt, Upcast}; @@ -18,6 +17,7 @@ use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, BytePos, DesugaringKind, Span}; use rustc_target::abi::FieldIdx; use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; use crate::diagnostics::BorrowedContentSource; diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 49f50babdcb..5d7ce548469 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -125,8 +125,8 @@ pub(crate) fn compute_regions<'cx, 'tcx>( placeholder_indices, placeholder_index_to_region: _, liveness_constraints, - outlives_constraints, - member_constraints, + mut outlives_constraints, + mut member_constraints, universe_causes, type_tests, } = constraints; @@ -144,6 +144,16 @@ pub(crate) fn compute_regions<'cx, 'tcx>( &universal_region_relations, ); + if let Some(guar) = universal_regions.tainted_by_errors() { + // Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all + // outlives bounds that we may end up checking. + outlives_constraints = Default::default(); + member_constraints = Default::default(); + + // Also taint the entire scope. + infcx.set_tainted_by_errors(guar); + } + let mut regioncx = RegionInferenceContext::new( infcx, var_origins, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index b57cf9066cf..0e3140ca98b 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -2304,5 +2304,5 @@ pub struct BlameConstraint<'tcx> { pub category: ConstraintCategory<'tcx>, pub from_closure: bool, pub cause: ObligationCause<'tcx>, - pub variance_info: ty::VarianceDiagInfo<'tcx>, + pub variance_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, } diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index f601a9d7073..06adb686ed4 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -340,7 +340,7 @@ fn check_opaque_type_well_formed<'tcx>( .with_next_trait_solver(next_trait_solver) .with_opaque_type_inference(parent_def_id) .build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let identity_args = GenericArgs::identity_for_item(tcx, def_id); // Require that the hidden type actually fulfills all the bounds of the opaque type, even without diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index b23ad2e1584..0cb4b15b127 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -10,9 +10,9 @@ use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_span::Span; -use rustc_trait_selection::solve::deeply_normalize; use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; +use rustc_trait_selection::traits::ScrubbedTraitError; use crate::{ constraints::OutlivesConstraint, @@ -282,11 +282,12 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { ) -> Ty<'tcx> { let result = CustomTypeOp::new( |ocx| { - deeply_normalize( - ocx.infcx.at(&ObligationCause::dummy_with_span(self.span), self.param_env), + ocx.deeply_normalize( + &ObligationCause::dummy_with_span(self.span), + self.param_env, ty, ) - .map_err(|_| NoSolution) + .map_err(|_: Vec<ScrubbedTraitError<'tcx>>| NoSolution) }, "normalize type outlives obligation", ) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 291d2782c32..fcfb297d50a 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -346,7 +346,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } else { let tcx = self.tcx(); let maybe_uneval = match constant.const_ { - Const::Ty(ct) => match ct.kind() { + Const::Ty(_, ct) => match ct.kind() { ty::ConstKind::Unevaluated(_) => { bug!("should not encounter unevaluated Const::Ty here, got {:?}", ct) } @@ -1856,7 +1856,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Operand::Constant(constant) = op { let maybe_uneval = match constant.const_ { - Const::Val(..) | Const::Ty(_) => None, + Const::Val(..) | Const::Ty(_, _) => None, Const::Unevaluated(uv, _) => Some(uv), }; diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index cbd8a4125cd..2c34fc583c8 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -1,14 +1,14 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorGuaranteed; +use rustc_infer::infer::relate::{ObligationEmittingRelation, StructurallyRelateAliases}; +use rustc_infer::infer::relate::{Relate, RelateResult, TypeRelation}; use rustc_infer::infer::NllRegionVariableOrigin; -use rustc_infer::infer::{ObligationEmittingRelation, StructurallyRelateAliases}; use rustc_infer::traits::{Obligation, PredicateObligations}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::span_bug; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::fold::FnMutDelegate; -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; @@ -82,7 +82,7 @@ pub struct NllTypeRelating<'me, 'bccx, 'tcx> { /// - Bivariant means that it doesn't matter. ambient_variance: ty::Variance, - ambient_variance_info: ty::VarianceDiagInfo<'tcx>, + ambient_variance_info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, } impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { @@ -193,7 +193,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { types: &mut |_bound_ty: ty::BoundTy| { unreachable!("we only replace regions in nll_relate, not types") }, - consts: &mut |_bound_var: ty::BoundVar, _ty| { + consts: &mut |_bound_var: ty::BoundVar| { unreachable!("we only replace regions in nll_relate, not consts") }, }; @@ -231,7 +231,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { types: &mut |_bound_ty: ty::BoundTy| { unreachable!("we only replace regions in nll_relate, not types") }, - consts: &mut |_bound_var: ty::BoundVar, _ty| { + consts: &mut |_bound_var: ty::BoundVar| { unreachable!("we only replace regions in nll_relate, not consts") }, }; @@ -296,7 +296,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { &mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>, - info: ty::VarianceDiagInfo<'tcx>, + info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, ) { let sub = self.type_checker.borrowck_context.universal_regions.to_region_vid(sub); let sup = self.type_checker.borrowck_context.universal_regions.to_region_vid(sup); @@ -314,7 +314,7 @@ impl<'me, 'bccx, 'tcx> NllTypeRelating<'me, 'bccx, 'tcx> { } } -impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> { +impl<'bccx, 'tcx> TypeRelation<TyCtxt<'tcx>> for NllTypeRelating<'_, 'bccx, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.type_checker.infcx.tcx } @@ -324,10 +324,10 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> { } #[instrument(skip(self, info), level = "trace", ret)] - fn relate_with_variance<T: Relate<'tcx>>( + fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>( &mut self, variance: ty::Variance, - info: ty::VarianceDiagInfo<'tcx>, + info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -445,7 +445,7 @@ impl<'bccx, 'tcx> TypeRelation<'tcx> for NllTypeRelating<'_, 'bccx, 'tcx> { b: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate<TyCtxt<'tcx>>, { // We want that // diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index f8123535e2d..9f5fb59e46c 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -29,7 +29,8 @@ use rustc_middle::ty::{self, InlineConstArgs, InlineConstArgsParts, RegionVid, T use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::{kw, sym}; -use rustc_span::Symbol; +use rustc_span::{ErrorGuaranteed, Symbol}; +use std::cell::Cell; use std::iter; use crate::renumber::RegionCtxt; @@ -186,6 +187,10 @@ struct UniversalRegionIndices<'tcx> { /// The vid assigned to `'static`. Used only for diagnostics. pub fr_static: RegionVid, + + /// Whether we've encountered an error region. If we have, cancel all + /// outlives errors, as they are likely bogus. + pub tainted_by_errors: Cell<Option<ErrorGuaranteed>>, } #[derive(Debug, PartialEq)] @@ -408,6 +413,10 @@ impl<'tcx> UniversalRegions<'tcx> { } } } + + pub fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> { + self.indices.tainted_by_errors.get() + } } struct UniversalRegionsBuilder<'cx, 'tcx> { @@ -663,7 +672,11 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static)); let arg_mapping = iter::zip(identity_args.regions(), fr_args.regions().map(|r| r.as_var())); - UniversalRegionIndices { indices: global_mapping.chain(arg_mapping).collect(), fr_static } + UniversalRegionIndices { + indices: global_mapping.chain(arg_mapping).collect(), + fr_static, + tainted_by_errors: Cell::new(None), + } } fn compute_inputs_and_output( @@ -868,7 +881,8 @@ impl<'tcx> UniversalRegionIndices<'tcx> { pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid { if let ty::ReVar(..) = *r { r.as_var() - } else if r.is_error() { + } else if let ty::ReError(guar) = *r { + self.tainted_by_errors.set(Some(guar)); // We use the `'static` `RegionVid` because `ReError` doesn't actually exist in the // `UniversalRegionIndices`. This is fine because 1) it is a fallback only used if // errors are being emitted and 2) it leaves the happy path unaffected. diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index a3d6a1c7360..2d1269e1b6a 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -110,6 +110,9 @@ builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept a builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values .suggestion = remove the value +builtin_macros_derive_unsafe_path = traits in `#[derive(...)]` don't accept `unsafe(...)` + .suggestion = remove the `unsafe(...)` + builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time .cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead .custom = use `std::env::var({$var_expr})` to read the variable at run time diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 78144226114..a98cb6f0f76 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -57,7 +57,6 @@ impl<'cx, 'a> Context<'cx, 'a> { /// Builds the whole `assert!` expression. For example, `let elem = 1; assert!(elem == 1);` expands to: /// /// ```rust - /// #![feature(generic_assert_internals)] /// let elem = 1; /// { /// #[allow(unused_imports)] diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 5f63a8ae0a8..03aff6f9633 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -196,7 +196,7 @@ impl CfgEval<'_, '_> { // Re-parse the tokens, setting the `capture_cfg` flag to save extra information // to the captured `AttrTokenStream` (specifically, we capture // `AttrTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`) - let mut parser = rustc_parse::stream_to_parser(&self.cfg.sess.psess, orig_tokens, None); + let mut parser = Parser::new(&self.cfg.sess.psess, orig_tokens, None); parser.capture_cfg = true; match parse_annotatable_with(&mut parser) { Ok(a) => annotatable = a, diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs index ada82e45712..16184ec7511 100644 --- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -4,19 +4,20 @@ use crate::errors; use rustc_ast::attr::mk_attr; use rustc_ast::token; use rustc_ast::{self as ast, AttrItem, AttrStyle}; +use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use rustc_span::FileName; pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) { for raw_attr in attrs { - let mut parser = rustc_parse::new_parser_from_source_str( + let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str( psess, FileName::cli_crate_attr_source_code(raw_attr), raw_attr.clone(), - ); + )); let start_span = parser.token.span; - let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) { + let AttrItem { unsafety, path, args, tokens: _ } = match parser.parse_attr_item(false) { Ok(ai) => ai, Err(err) => { err.emit(); @@ -32,6 +33,7 @@ pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) { krate.attrs.push(mk_attr( &psess.attr_id_generator, AttrStyle::Inner, + unsafety, path, args, start_span.to(end_span), diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index d14858e5c1d..b5cbfdf0ec6 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -2,7 +2,7 @@ use crate::cfg_eval::cfg_eval; use crate::errors; use rustc_ast as ast; -use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind}; +use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, Safety, StmtKind}; use rustc_expand::base::{ Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier, }; @@ -60,6 +60,7 @@ impl MultiItemModifier for Expander { // Reject `#[derive(Debug = "value", Debug(abc))]`, but recover the // paths. report_path_args(sess, meta); + report_unsafe_args(sess, meta); meta.path.clone() }) .map(|path| DeriveResolution { @@ -159,3 +160,13 @@ fn report_path_args(sess: &Session, meta: &ast::MetaItem) { } } } + +fn report_unsafe_args(sess: &Session, meta: &ast::MetaItem) { + match meta.unsafety { + Safety::Unsafe(span) => { + sess.dcx().emit_err(errors::DeriveUnsafePath { span }); + } + Safety::Default => {} + Safety::Safe(_) => unreachable!(), + } +} diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 217fa5ff9f1..ba289f9552e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -412,6 +412,15 @@ fn find_type_parameters( impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> { fn visit_ty(&mut self, ty: &'a ast::Ty) { + let stack_len = self.bound_generic_params_stack.len(); + if let ast::TyKind::BareFn(bare_fn) = &ty.kind + && !bare_fn.generic_params.is_empty() + { + // Given a field `x: for<'a> fn(T::SomeType<'a>)`, we wan't to account for `'a` so + // that we generate `where for<'a> T::SomeType<'a>: ::core::clone::Clone`. #122622 + self.bound_generic_params_stack.extend(bare_fn.generic_params.iter().cloned()); + } + if let ast::TyKind::Path(_, path) = &ty.kind && let Some(segment) = path.segments.first() && self.ty_param_names.contains(&segment.ident.name) @@ -422,7 +431,8 @@ fn find_type_parameters( }); } - visit::walk_ty(self, ty) + visit::walk_ty(self, ty); + self.bound_generic_params_stack.truncate(stack_len); } // Place bound generic params on a stack, to extract them when a type is encountered. diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index d157703723b..b14eb2b5ee6 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -296,6 +296,13 @@ pub(crate) struct DerivePathArgsValue { } #[derive(Diagnostic)] +#[diag(builtin_macros_derive_unsafe_path)] +pub(crate) struct DeriveUnsafePath { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] #[diag(builtin_macros_no_default_variant)] #[help] pub(crate) struct NoDefaultVariant { diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 29e991525a9..dc1d82df0c3 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -12,8 +12,8 @@ use rustc_expand::base::{ }; use rustc_expand::module::DirOwnership; use rustc_lint_defs::BuiltinLintDiag; -use rustc_parse::new_parser_from_file; use rustc_parse::parser::{ForceCollect, Parser}; +use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; use rustc_span::source_map::SourceMap; use rustc_span::symbol::Symbol; @@ -126,7 +126,7 @@ pub(crate) fn expand_include<'cx>( return ExpandResult::Ready(DummyResult::any(sp, guar)); } }; - let p = new_parser_from_file(cx.psess(), &file, Some(sp)); + let p = unwrap_or_emit_fatal(new_parser_from_file(cx.psess(), &file, Some(sp))); // If in the included file we have e.g., `mod bar;`, // then the path of `bar.rs` should be relative to the directory of `file`. diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 38ac2f15fe7..ba4e5cfd130 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -203,6 +203,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> { let allow_dead_code = attr::mk_attr_nested_word( &self.sess.psess.attr_id_generator, ast::AttrStyle::Outer, + ast::Safety::Default, sym::allow, sym::dead_code, self.def_site, diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 963e5de91ce..6d26ca0b899 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -832,9 +832,10 @@ fn codegen_stmt<'tcx>( let val = match null_op { NullOp::SizeOf => layout.size.bytes(), NullOp::AlignOf => layout.align.abi.bytes(), - NullOp::OffsetOf(fields) => { - layout.offset_of_subfield(fx, fields.iter()).bytes() - } + NullOp::OffsetOf(fields) => fx + .tcx + .offset_of_subfield(ParamEnv::reveal_all(), layout, fields.iter()) + .bytes(), NullOp::UbChecks => { let val = fx.tcx.sess.ub_checks(); let val = CValue::by_val( diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index ba98f2e772c..a53598018f4 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -110,7 +110,7 @@ pub(crate) fn codegen_const_value<'tcx>( if fx.clif_type(layout.ty).is_some() { return CValue::const_val(fx, layout, int); } else { - let raw_val = int.size().truncate(int.assert_bits(int.size())); + let raw_val = int.size().truncate(int.to_bits(int.size())); let val = match int.size().bytes() { 1 => fx.bcx.ins().iconst(types::I8, raw_val as i64), 2 => fx.bcx.ins().iconst(types::I16, raw_val as i64), @@ -501,12 +501,12 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( Ordering::Equal => scalar_int, Ordering::Less => match ty.kind() { ty::Uint(_) => ScalarInt::try_from_uint( - scalar_int.assert_uint(scalar_int.size()), + scalar_int.to_uint(scalar_int.size()), fx.layout_of(*ty).size, ) .unwrap(), ty::Int(_) => ScalarInt::try_from_int( - scalar_int.assert_int(scalar_int.size()), + scalar_int.to_int(scalar_int.size()), fx.layout_of(*ty).size, ) .unwrap(), diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 394c810176a..dcafac21bc7 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -288,6 +288,29 @@ fn produce_final_output_artifacts( } } + if sess.opts.json_artifact_notifications { + if codegen_results.modules.len() == 1 { + codegen_results.modules[0].for_each_output(|_path, ty| { + if sess.opts.output_types.contains_key(&ty) { + let descr = ty.shorthand(); + // for single cgu file is renamed to drop cgu specific suffix + // so we regenerate it the same way + let path = crate_output.path(ty); + sess.dcx().emit_artifact_notification(path.as_path(), descr); + } + }); + } else { + for module in &codegen_results.modules { + module.for_each_output(|path, ty| { + if sess.opts.output_types.contains_key(&ty) { + let descr = ty.shorthand(); + sess.dcx().emit_artifact_notification(&path, descr); + } + }); + } + } + } + // We leave the following files around by default: // - #crate#.o // - #crate#.crate.metadata.o diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs index 27b55ecc72e..d454f3c1de7 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs @@ -902,7 +902,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( .span_fatal(span, "Index argument for `_mm_cmpestri` is not a constant"); }; - let imm8 = imm8.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", imm8)); + let imm8 = imm8.to_u8(); codegen_inline_asm_inner( fx, @@ -955,7 +955,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( .span_fatal(span, "Index argument for `_mm_cmpestrm` is not a constant"); }; - let imm8 = imm8.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", imm8)); + let imm8 = imm8.to_u8(); codegen_inline_asm_inner( fx, @@ -1003,7 +1003,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( ); }; - let imm8 = imm8.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", imm8)); + let imm8 = imm8.to_u8(); codegen_inline_asm_inner( fx, @@ -1040,7 +1040,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( ); }; - let imm8 = imm8.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", imm8)); + let imm8 = imm8.to_u8(); codegen_inline_asm_inner( fx, @@ -1195,7 +1195,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( .span_fatal(span, "Func argument for `_mm_sha1rnds4_epu32` is not a constant"); }; - let func = func.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", func)); + let func = func.to_u8(); codegen_inline_asm_inner( fx, diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index b17f191ce26..ca910dccb0d 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -133,6 +133,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( .expect_const() .eval(fx.tcx, ty::ParamEnv::reveal_all(), span) .unwrap() + .1 .unwrap_branch(); assert_eq!(x.layout(), y.layout()); @@ -146,8 +147,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let total_len = lane_count * 2; - let indexes = - idx.iter().map(|idx| idx.unwrap_leaf().try_to_u32().unwrap()).collect::<Vec<u32>>(); + let indexes = idx.iter().map(|idx| idx.unwrap_leaf().to_u32()).collect::<Vec<u32>>(); for &idx in &indexes { assert!(u64::from(idx) < total_len, "idx {} out of range 0..{}", idx, total_len); @@ -281,9 +281,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( fx.tcx.dcx().span_fatal(span, "Index argument for `simd_insert` is not a constant"); }; - let idx: u32 = idx_const - .try_to_u32() - .unwrap_or_else(|_| panic!("kind not scalar: {:?}", idx_const)); + let idx: u32 = idx_const.to_u32(); let (lane_count, _lane_ty) = base.layout().ty.simd_size_and_type(fx.tcx); if u64::from(idx) >= lane_count { fx.tcx.dcx().span_fatal( @@ -329,9 +327,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( return; }; - let idx = idx_const - .try_to_u32() - .unwrap_or_else(|_| panic!("kind not scalar: {:?}", idx_const)); + let idx = idx_const.to_u32(); let (lane_count, _lane_ty) = v.layout().ty.simd_size_and_type(fx.tcx); if u64::from(idx) >= lane_count { fx.tcx.dcx().span_fatal( diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 512a96450a4..1aa28daeafc 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -327,7 +327,7 @@ impl<'tcx> CValue<'tcx> { let val = match layout.ty.kind() { ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => { - let const_val = const_val.assert_bits(layout.size); + let const_val = const_val.to_bits(layout.size); let lsb = fx.bcx.ins().iconst(types::I64, const_val as u64 as i64); let msb = fx.bcx.ins().iconst(types::I64, (const_val >> 64) as u64 as i64); fx.bcx.ins().iconcat(lsb, msb) @@ -339,7 +339,7 @@ impl<'tcx> CValue<'tcx> { | ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) => { - let raw_val = const_val.size().truncate(const_val.assert_bits(layout.size)); + let raw_val = const_val.size().truncate(const_val.to_bits(layout.size)); fx.bcx.ins().iconst(clif_ty, raw_val as i64) } ty::Float(FloatTy::F32) => { diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 78d943192db..548c23cc794 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -166,7 +166,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; match cv { Scalar::Int(int) => { - let data = int.assert_bits(layout.size(self)); + let data = int.to_bits(layout.size(self)); // FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code // the paths for floating-point values. diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index fa7e7e5377a..a354f3d3536 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -128,11 +128,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { is_direct_dependency: bool, ) -> PathBuf { let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" }; - let output_path = { - let mut output_path: PathBuf = tmpdir.to_path_buf(); - output_path.push(format!("{lib_name}{name_suffix}")); - output_path.with_extension("lib") - }; + let output_path = tmpdir.join(format!("{lib_name}{name_suffix}.lib")); let target = &sess.target; let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(target); @@ -157,8 +153,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder { // that loaded but crashed with an AV upon calling one of the imported // functions. Therefore, use binutils to create the import library instead, // by writing a .DEF file to the temp dir and calling binutils's dlltool. - let def_file_path = - tmpdir.join(format!("{lib_name}{name_suffix}")).with_extension("def"); + let def_file_path = tmpdir.join(format!("{lib_name}{name_suffix}.def")); let def_file_content = format!( "EXPORTS\n{}", diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index ab8036a1410..4ffc92eb633 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -244,7 +244,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; match cv { Scalar::Int(int) => { - let data = int.assert_bits(layout.size(self)); + let data = int.to_bits(layout.size(self)); let llval = self.const_uint_big(self.type_ix(bitsize), data); if matches!(layout.primitive(), Pointer(_)) { unsafe { llvm::LLVMConstIntToPtr(llval, llty) } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 39bbf87bea7..b5b0086f740 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1109,10 +1109,12 @@ fn generic_simd_intrinsic<'ll, 'tcx>( tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx)); let arg_tys = sig.inputs(); - // Vectors must be immediates (non-power-of-2 #[repr(packed)] are not) - for (ty, arg) in arg_tys.iter().zip(args) { - if ty.is_simd() && !matches!(arg.val, OperandValue::Immediate(_)) { - return_error!(InvalidMonomorphization::SimdArgument { span, name, ty: *ty }); + // Sanity-check: all vector arguments must be immediates. + if cfg!(debug_assertions) { + for (ty, arg) in arg_tys.iter().zip(args) { + if ty.is_simd() { + assert!(matches!(arg.val, OperandValue::Immediate(_))); + } } } @@ -1201,6 +1203,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( .expect_const() .eval(tcx, ty::ParamEnv::reveal_all(), span) .unwrap() + .1 .unwrap_branch(); let n = idx.len() as u64; @@ -1220,7 +1223,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( .iter() .enumerate() .map(|(arg_idx, val)| { - let idx = val.unwrap_leaf().try_to_i32().unwrap(); + let idx = val.unwrap_leaf().to_i32(); if idx >= i32::try_from(total_len).unwrap() { bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds { span, diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs index 3114f1c38ae..f499bbcf853 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs @@ -85,6 +85,11 @@ fn get_rpath_relative_to_output(config: &RPathConfig<'_>, lib: &Path) -> OsStrin // Strip filenames let lib = lib.parent().unwrap(); let output = config.out_filename.parent().unwrap(); + + // If output or lib is empty, just assume it locates in current path + let lib = if lib == Path::new("") { Path::new(".") } else { lib }; + let output = if output == Path::new("") { Path::new(".") } else { output }; + let lib = try_canonicalize(lib).unwrap(); let output = try_canonicalize(output).unwrap(); let relative = path_relative_from(&lib, &output) diff --git a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs index ac2e54072c4..0de90a1036e 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs @@ -58,6 +58,22 @@ fn test_rpath_relative() { } #[test] +fn test_rpath_relative_issue_119571() { + let config = &mut RPathConfig { + libs: &[], + out_filename: PathBuf::from("rustc"), + has_rpath: true, + is_like_osx: false, + linker_is_gnu: true, + }; + // Should not panic when out_filename only contains filename. + // Issue 119571 + let _ = get_rpath_relative_to_output(config, Path::new("lib/libstd.so")); + // Should not panic when lib only contains filename. + let _ = get_rpath_relative_to_output(config, Path::new("libstd.so")); +} + +#[test] fn test_xlinker() { let args = rpaths_to_flags(vec!["a/normal/path".into(), "a,comma,path".into()]); diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 79d6641a0da..a6df8950b35 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -400,7 +400,7 @@ fn upstream_monomorphizations_provider( tcx: TyCtxt<'_>, (): (), ) -> DefIdMap<UnordMap<GenericArgsRef<'_>, CrateNum>> { - let cnums = tcx.used_crates(()); + let cnums = tcx.crates(()); let mut instances: DefIdMap<UnordMap<_, _>> = Default::default(); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index d57f4ddf8aa..dec87db0fc5 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -717,6 +717,29 @@ fn produce_final_output_artifacts( } } + if sess.opts.json_artifact_notifications { + if compiled_modules.modules.len() == 1 { + compiled_modules.modules[0].for_each_output(|_path, ty| { + if sess.opts.output_types.contains_key(&ty) { + let descr = ty.shorthand(); + // for single cgu file is renamed to drop cgu specific suffix + // so we regenerate it the same way + let path = crate_output.path(ty); + sess.dcx().emit_artifact_notification(path.as_path(), descr); + } + }); + } else { + for module in &compiled_modules.modules { + module.for_each_output(|path, ty| { + if sess.opts.output_types.contains_key(&ty) { + let descr = ty.shorthand(); + sess.dcx().emit_artifact_notification(&path, descr); + } + }); + } + } + } + // We leave the following files around by default: // - #crate#.o // - #crate#.crate.metadata.o diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index f372d3a0522..0b450c43924 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -541,7 +541,7 @@ pub fn collect_debugger_visualizers_transitive( tcx.debugger_visualizers(LOCAL_CRATE) .iter() .chain( - tcx.used_crates(()) + tcx.crates(()) .iter() .filter(|&cnum| { let used_crate_source = tcx.used_crate_source(*cnum); @@ -851,7 +851,7 @@ impl CrateInfo { // `compiler_builtins` are always placed last to ensure that they're linked correctly. used_crates.extend(compiler_builtins); - let crates = tcx.used_crates(()); + let crates = tcx.crates(()); let n_crates = crates.len(); let mut info = CrateInfo { target_cpu, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 5d7257b15c4..15955170e87 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -324,21 +324,22 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let linkage = Some(linkage_by_name(tcx, did, val.as_str())); if tcx.is_foreign_item(did) { codegen_fn_attrs.import_linkage = linkage; + + if tcx.is_mutable_static(did.into()) { + let mut diag = tcx.dcx().struct_span_err( + attr.span, + "extern mutable statics are not allowed with `#[linkage]`", + ); + diag.note( + "marking the extern static mutable would allow changing which symbol \ + the static references rather than make the target of the symbol \ + mutable", + ); + diag.emit(); + } } else { codegen_fn_attrs.linkage = linkage; } - if tcx.is_mutable_static(did.into()) { - let mut diag = tcx.dcx().struct_span_err( - attr.span, - "mutable statics are not allowed with `#[linkage]`", - ); - diag.note( - "making the static mutable would allow changing which symbol the \ - static references rather than make the target of the symbol \ - mutable", - ); - diag.emit(); - } } } sym::link_section => { diff --git a/compiler/rustc_codegen_ssa/src/common.rs b/compiler/rustc_codegen_ssa/src/common.rs index e4a36b3f591..27b0f127e92 100644 --- a/compiler/rustc_codegen_ssa/src/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -163,7 +163,7 @@ pub fn asm_const_to_str<'tcx>( let mir::ConstValue::Scalar(scalar) = const_value else { span_bug!(sp, "expected Scalar for promoted asm const, but got {:#?}", const_value) }; - let value = scalar.assert_bits(ty_and_layout.size); + let value = scalar.assert_scalar_int().to_bits(ty_and_layout.size); match ty_and_layout.ty.kind() { ty::Uint(_) => value.to_string(), ty::Int(int_ty) => match int_ty.normalize(tcx.sess.target.pointer_width) { diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 07473ee476b..c4e5c858240 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -263,7 +263,7 @@ fn push_debuginfo_type_name<'tcx>( let ExistentialProjection { def_id: item_def_id, term, .. } = tcx.instantiate_bound_regions_with_erased(bound); // FIXME(associated_const_equality): allow for consts here - (item_def_id, term.ty().unwrap()) + (item_def_id, term.expect_type()) }) .collect(); @@ -693,41 +693,46 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S ty::ConstKind::Param(param) => { write!(output, "{}", param.name) } - _ => match ct.ty().kind() { - ty::Int(ity) => { - let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all()); - let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; - write!(output, "{val}") - } - ty::Uint(_) => { - let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all()); - write!(output, "{val}") - } - ty::Bool => { - let val = ct.try_eval_bool(tcx, ty::ParamEnv::reveal_all()).unwrap(); - write!(output, "{val}") - } - _ => { - // If we cannot evaluate the constant to a known type, we fall back - // to emitting a stable hash value of the constant. This isn't very pretty - // but we get a deterministic, virtually unique value for the constant. - // - // Let's only emit 64 bits of the hash value. That should be plenty for - // avoiding collisions and will make the emitted type names shorter. - let hash_short = tcx.with_stable_hashing_context(|mut hcx| { - let mut hasher = StableHasher::new(); - let ct = ct.eval(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP).unwrap(); - hcx.while_hashing_spans(false, |hcx| ct.hash_stable(hcx, &mut hasher)); - hasher.finish::<Hash64>() - }); - - if cpp_like_debuginfo(tcx) { - write!(output, "CONST${hash_short:x}") - } else { - write!(output, "{{CONST#{hash_short:x}}}") + ty::ConstKind::Value(ty, _) => { + match ty.kind() { + ty::Int(ity) => { + // FIXME: directly extract the bits from a valtree instead of evaluating an + // alreay evaluated `Const` in order to get the bits. + let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all()); + let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; + write!(output, "{val}") + } + ty::Uint(_) => { + let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all()); + write!(output, "{val}") + } + ty::Bool => { + let val = ct.try_eval_bool(tcx, ty::ParamEnv::reveal_all()).unwrap(); + write!(output, "{val}") + } + _ => { + // If we cannot evaluate the constant to a known type, we fall back + // to emitting a stable hash value of the constant. This isn't very pretty + // but we get a deterministic, virtually unique value for the constant. + // + // Let's only emit 64 bits of the hash value. That should be plenty for + // avoiding collisions and will make the emitted type names shorter. + let hash_short = tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + let ct = ct.eval(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP).unwrap(); + hcx.while_hashing_spans(false, |hcx| ct.hash_stable(hcx, &mut hasher)); + hasher.finish::<Hash64>() + }); + + if cpp_like_debuginfo(tcx) { + write!(output, "CONST${hash_short:x}") + } else { + write!(output, "{{CONST#{hash_short:x}}}") + } } } - }, + } + _ => bug!("Invalid `Const` during codegen: {:?}", ct), } .unwrap(); } diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 1668104d7e2..3b1921d40e6 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -106,6 +106,24 @@ pub struct CompiledModule { pub llvm_ir: Option<PathBuf>, // --emit=llvm-ir, llvm-bc is in bytecode } +impl CompiledModule { + /// Call `emit` function with every artifact type currently compiled + pub fn for_each_output(&self, mut emit: impl FnMut(&Path, OutputType)) { + if let Some(path) = self.object.as_deref() { + emit(path, OutputType::Object); + } + if let Some(path) = self.bytecode.as_deref() { + emit(path, OutputType::Bitcode); + } + if let Some(path) = self.llvm_ir.as_deref() { + emit(path, OutputType::LlvmAssembly); + } + if let Some(path) = self.assembly.as_deref() { + emit(path, OutputType::Assembly); + } + } +} + pub struct CachedModuleCodegen { pub name: String, pub source: WorkProduct, diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index dba5fbefd8a..822f5c2c44a 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -40,10 +40,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> Result<Option<ty::ValTree<'tcx>>, ErrorHandled> { let uv = match self.monomorphize(constant.const_) { mir::Const::Unevaluated(uv, _) => uv.shrink(), - mir::Const::Ty(c) => match c.kind() { + mir::Const::Ty(_, c) => match c.kind() { // A constant that came from a const generic but was then used as an argument to old-style // simd_shuffle (passing as argument instead of as a generic param). - rustc_type_ir::ConstKind::Value(valtree) => return Ok(Some(valtree)), + rustc_type_ir::ConstKind::Value(_, valtree) => return Ok(Some(valtree)), other => span_bug!(constant.span, "{other:#?}"), }, // We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index c23867be3a1..ad6b3f1159d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -680,7 +680,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.cx().const_usize(val) } mir::NullOp::OffsetOf(fields) => { - let val = layout.offset_of_subfield(bx.cx(), fields.iter()).bytes(); + let val = bx + .tcx() + .offset_of_subfield(bx.param_env(), layout, fields.iter()) + .bytes(); bx.cx().const_usize(val) } mir::NullOp::UbChecks => { diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 5fbf5b41109..9e01c59a96f 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -735,7 +735,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // which path expressions are getting called on and which path expressions are only used // as function pointers. This is required for correctness. let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let predicates = tcx.predicates_of(callee).instantiate(tcx, fn_args); let cause = ObligationCause::new( diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index 5949444e599..9fd7219499b 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -357,15 +357,15 @@ where // Check the qualifs of the value of `const` items. let uneval = match constant.const_ { - Const::Ty(ct) + Const::Ty(_, ct) if matches!( ct.kind(), - ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_) + ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_, _) ) => { None } - Const::Ty(c) => { + Const::Ty(_, c) => { bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", c) } Const::Unevaluated(uv, _) => Some(uv), diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index 3c11d67e748..8c66888d100 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -38,6 +38,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { match node { hir::Node::Ctor(_) | hir::Node::AnonConst(_) + | hir::Node::ConstBlock(_) | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => { hir::Constness::Const } @@ -56,7 +57,6 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness { if is_const { hir::Constness::Const } else { hir::Constness::NotConst } } hir::Node::Expr(e) if let hir::ExprKind::Closure(c) = e.kind => c.constness, - hir::Node::Expr(e) if let hir::ExprKind::ConstBlock(_) = e.kind => hir::Constness::Const, _ => { if let Some(fn_kind) = node.fn_kind() { if fn_kind.constness() == hir::Constness::Const { diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 5312f1f946f..66993476bef 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -95,10 +95,10 @@ fn const_to_valtree_inner<'tcx>( } ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { let val = ecx.read_immediate(place)?; - let val = val.to_scalar(); + let val = val.to_scalar_int().unwrap(); *num_nodes += 1; - Ok(ty::ValTree::Leaf(val.assert_int())) + Ok(ty::ValTree::Leaf(val)) } ty::Pat(base, ..) => { @@ -125,7 +125,7 @@ fn const_to_valtree_inner<'tcx>( let val = val.to_scalar(); // We are in the CTFE machine, so ptr-to-int casts will fail. // This can only be `Ok` if `val` already is an integer. - let Ok(val) = val.try_to_int() else { + let Ok(val) = val.try_to_scalar_int() else { return Err(ValTreeCreationError::NonSupportedType); }; // It's just a ScalarInt! @@ -411,7 +411,7 @@ fn valtree_into_mplace<'tcx>( ty::Adt(def, _) if def.is_enum() => { // First element of valtree corresponds to variant let scalar_int = branches[0].unwrap_leaf(); - let variant_idx = VariantIdx::from_u32(scalar_int.try_to_u32().unwrap()); + let variant_idx = VariantIdx::from_u32(scalar_int.to_u32()); let variant = def.variant(variant_idx); debug!(?variant); diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 67fbf9642bf..0dbee8c1d94 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -123,14 +123,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // (`tag_bits` itself is only used for error messages below.) let tag_bits = tag_val .to_scalar() - .try_to_int() + .try_to_scalar_int() .map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))? - .assert_bits(tag_layout.size); + .to_bits(tag_layout.size); // Cast bits from tag layout to discriminant layout. // After the checks we did above, this cannot fail, as // discriminants are int-like. let discr_val = self.int_to_int_or_float(&tag_val, discr_layout).unwrap(); - let discr_bits = discr_val.to_scalar().assert_bits(discr_layout.size); + let discr_bits = discr_val.to_scalar().to_bits(discr_layout.size)?; // Convert discriminant to variant index, and catch invalid discriminants. let index = match *ty.kind() { ty::Adt(adt, _) => { @@ -152,7 +152,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // discriminant (encoded in niche/tag) and variant index are the same. let variants_start = niche_variants.start().as_u32(); let variants_end = niche_variants.end().as_u32(); - let variant = match tag_val.try_to_int() { + let variant = match tag_val.try_to_scalar_int() { Err(dbg_val) => { // So this is a pointer then, and casting to an int failed. // Can only happen during CTFE. @@ -167,7 +167,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { untagged_variant } Ok(tag_bits) => { - let tag_bits = tag_bits.assert_bits(tag_layout.size); + let tag_bits = tag_bits.to_bits(tag_layout.size); // We need to use machine arithmetic to get the relative variant idx: // variant_index_relative = tag_val - niche_start_val let tag_val = ImmTy::from_uint(tag_bits, tag_layout); @@ -175,7 +175,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let variant_index_relative_val = self.binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?; let variant_index_relative = - variant_index_relative_val.to_scalar().assert_bits(tag_val.layout.size); + variant_index_relative_val.to_scalar().to_bits(tag_val.layout.size)?; // Check if this is in the range that indicates an actual discriminant. if variant_index_relative <= u128::from(variants_end - variants_start) { let variant_index_relative = u32::try_from(variant_index_relative) @@ -294,8 +294,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ImmTy::from_uint(variant_index_relative, tag_layout); let tag = self .binary_op(mir::BinOp::Add, &variant_index_relative_val, &niche_start_val)? - .to_scalar() - .assert_int(); + .to_scalar_int()?; Ok(Some((tag, tag_field))) } } diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 8d0b267e1a9..3066e0933d9 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -102,7 +102,7 @@ fn intern_as_new_static<'tcx>( let feed = tcx.create_def( static_id, sym::nested, - DefKind::Static { mutability: alloc.0.mutability, nested: true }, + DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true }, ); tcx.set_nested_alloc_id_static(alloc_id, feed.def_id()); diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 18b76443cd9..dac5c10addc 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -519,7 +519,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`. // First, check x % y != 0 (or if that computation overflows). let rem = self.binary_op(BinOp::Rem, a, b)?; - if rem.to_scalar().assert_bits(a.layout.size) != 0 { + if rem.to_scalar().to_bits(a.layout.size)? != 0 { throw_ub_custom!( fluent::const_eval_exact_div_has_remainder, a = format!("{a}"), diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 521f28b7123..7eb73e9b52f 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1344,7 +1344,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Test if this value might be null. /// If the machine does not support ptr-to-int casts, this is conservative. pub fn scalar_may_be_null(&self, scalar: Scalar<M::Provenance>) -> InterpResult<'tcx, bool> { - Ok(match scalar.try_to_int() { + Ok(match scalar.try_to_scalar_int() { Ok(int) => int.is_null(), Err(_) => { // Can only happen during CTFE. diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index bbb2c2f3938..0a7e9853763 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -89,6 +89,12 @@ impl<Prov: Provenance> Immediate<Prov> { #[inline] #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) + pub fn to_scalar_int(self) -> ScalarInt { + self.to_scalar().try_to_scalar_int().unwrap() + } + + #[inline] + #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) pub fn to_scalar_pair(self) -> (Scalar<Prov>, Scalar<Prov>) { match self { Immediate::ScalarPair(val1, val2) => (val1, val2), @@ -220,19 +226,11 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { } #[inline] - pub fn try_from_uint(i: impl Into<u128>, layout: TyAndLayout<'tcx>) -> Option<Self> { - Some(Self::from_scalar(Scalar::try_from_uint(i, layout.size)?, layout)) - } - #[inline] pub fn from_uint(i: impl Into<u128>, layout: TyAndLayout<'tcx>) -> Self { Self::from_scalar(Scalar::from_uint(i, layout.size), layout) } #[inline] - pub fn try_from_int(i: impl Into<i128>, layout: TyAndLayout<'tcx>) -> Option<Self> { - Some(Self::from_scalar(Scalar::try_from_int(i, layout.size)?, layout)) - } - #[inline] pub fn from_int(i: impl Into<i128>, layout: TyAndLayout<'tcx>) -> Self { Self::from_scalar(Scalar::from_int(i, layout.size), layout) } @@ -276,7 +274,8 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] pub fn to_const_int(self) -> ConstInt { assert!(self.layout.ty.is_integral()); - let int = self.to_scalar().assert_int(); + let int = self.imm.to_scalar_int(); + assert_eq!(int.size(), self.layout.size); ConstInt::new(int, self.layout.ty.is_signed(), self.layout.ty.is_ptr_sized_integral()) } diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 6d005dfcd86..c821c98073d 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -95,10 +95,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let l = left.to_scalar_int()?; let r = right.to_scalar_int()?; // Prepare to convert the values to signed or unsigned form. - let l_signed = || l.assert_int(left.layout.size); - let l_unsigned = || l.assert_uint(left.layout.size); - let r_signed = || r.assert_int(right.layout.size); - let r_unsigned = || r.assert_uint(right.layout.size); + let l_signed = || l.to_int(left.layout.size); + let l_unsigned = || l.to_uint(left.layout.size); + let r_signed = || r.to_int(right.layout.size); + let r_unsigned = || r.to_uint(right.layout.size); let throw_ub_on_overflow = match bin_op { AddUnchecked => Some(sym::unchecked_add), diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 4a86ec3f57a..046ff34e3d0 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -499,13 +499,14 @@ where &self, mplace: &MPlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> { - // Basically we just transmute this place into an array following simd_size_and_type. - // (Transmuting is okay since this is an in-memory place. We also double-check the size - // stays the same.) + // Basically we want to transmute this place into an array following simd_size_and_type. let (len, e_ty) = mplace.layout.ty.simd_size_and_type(*self.tcx); - let array = Ty::new_array(self.tcx.tcx, e_ty, len); - let layout = self.layout_of(array)?; - let mplace = mplace.transmute(layout, self)?; + // Some SIMD types have padding, so `len` many `e_ty` does not cover the entire place. + // Therefore we cannot transmute, and instead we project at offset 0, which side-steps + // the size check. + let array_layout = self.layout_of(Ty::new_array(self.tcx.tcx, e_ty, len))?; + assert!(array_layout.size <= mplace.layout.size); + let mplace = mplace.offset(Size::ZERO, array_layout, self)?; Ok((mplace, len)) } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 0e594914c3a..09e1a59dfa1 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -81,6 +81,8 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug { ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, Self> { assert!(layout.is_sized()); + // We sometimes do pointer arithmetic with this function, disregarding the source type. + // So we don't check the sizes here. self.offset_with_meta(offset, OffsetMode::Inbounds, MemPlaceMeta::None, layout, ecx) } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index d0bb821862a..1baf62baa81 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -253,7 +253,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Scalar::from_target_usize(val, self) } mir::NullOp::OffsetOf(fields) => { - let val = layout.offset_of_subfield(self, fields.iter()).bytes(); + let val = self + .tcx + .offset_of_subfield(self.param_env, layout, fields.iter()) + .bytes(); Scalar::from_target_usize(val, self) } mir::NullOp::UbChecks => Scalar::from_bool(self.tcx.sess.ub_checks()), diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 0649bb5617c..cbfe25ca8df 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -294,17 +294,30 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Unwrap types that are guaranteed a null-pointer-optimization fn unfold_npo(&self, layout: TyAndLayout<'tcx>) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - // Check if this is `Option` wrapping some type. - let inner = match layout.ty.kind() { - ty::Adt(def, args) if self.tcx.is_diagnostic_item(sym::Option, def.did()) => { - args[0].as_type().unwrap() - } - _ => { - // Not an `Option`. - return Ok(layout); + // Check if this is `Option` wrapping some type or if this is `Result` wrapping a 1-ZST and + // another type. + let ty::Adt(def, args) = layout.ty.kind() else { + // Not an ADT, so definitely no NPO. + return Ok(layout); + }; + let inner = if self.tcx.is_diagnostic_item(sym::Option, def.did()) { + // The wrapped type is the only arg. + self.layout_of(args[0].as_type().unwrap())? + } else if self.tcx.is_diagnostic_item(sym::Result, def.did()) { + // We want to extract which (if any) of the args is not a 1-ZST. + let lhs = self.layout_of(args[0].as_type().unwrap())?; + let rhs = self.layout_of(args[1].as_type().unwrap())?; + if lhs.is_1zst() { + rhs + } else if rhs.is_1zst() { + lhs + } else { + return Ok(layout); // no NPO } + } else { + return Ok(layout); // no NPO }; - let inner = self.layout_of(inner)?; + // Check if the inner type is one of the NPO-guaranteed ones. // For that we first unpeel transparent *structs* (but not unions). let is_npo = |def: AdtDef<'tcx>| { diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index e35ce9ef28d..f532f6bbe37 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -653,8 +653,8 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { let WrappingRange { start, end } = valid_range; let max_value = size.unsigned_int_max(); assert!(end <= max_value); - let bits = match scalar.try_to_int() { - Ok(int) => int.assert_bits(size), + let bits = match scalar.try_to_scalar_int() { + Ok(int) => int.to_bits(size), Err(_) => { // So this is a pointer then, and casting to an int failed. // Can only happen during CTFE. @@ -711,7 +711,9 @@ fn mutability<'tcx>(ecx: &InterpCx<'tcx, impl Machine<'tcx>>, alloc_id: AllocId) // We're not using `try_global_alloc` since dangling pointers have already been handled. match ecx.tcx.global_alloc(alloc_id) { GlobalAlloc::Static(did) => { - let DefKind::Static { mutability, nested } = ecx.tcx.def_kind(did) else { bug!() }; + let DefKind::Static { safety: _, mutability, nested } = ecx.tcx.def_kind(did) else { + bug!() + }; if nested { assert!( ecx.memory.alloc_map.get(alloc_id).is_none(), diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 2b61e17efa2..6876046a583 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -16,7 +16,6 @@ libc = "0.2" measureme = "11" rustc-hash = "1.1.0" rustc-rayon = { version = "0.5.0", optional = true } -rustc-rayon-core = { version = "0.5.0", optional = true } rustc_arena = { path = "../rustc_arena" } rustc_graphviz = { path = "../rustc_graphviz" } rustc_index = { path = "../rustc_index", package = "rustc_index" } @@ -52,5 +51,5 @@ portable-atomic = "1.5.1" [features] # tidy-alphabetical-start -rustc_use_parallel_compiler = ["indexmap/rustc-rayon", "rustc-rayon", "rustc-rayon-core"] +rustc_use_parallel_compiler = ["indexmap/rustc-rayon", "rustc-rayon"] # tidy-alphabetical-end diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 5f7504add8d..91cbffcd707 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -19,7 +19,6 @@ rustc_errors = { path = "../rustc_errors" } rustc_expand = { path = "../rustc_expand" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } -rustc_hir = { path = "../rustc_hir" } rustc_hir_analysis = { path = "../rustc_hir_analysis" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_hir_typeck = { path = "../rustc_hir_typeck" } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 08b97b4953e..93a65290602 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -32,6 +32,7 @@ use rustc_interface::{interface, Queries}; use rustc_lint::unerased_lint_store; use rustc_metadata::creader::MetadataLoader; use rustc_metadata::locator; +use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS}; use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType}; use rustc_session::getopts::{self, Matches}; @@ -814,13 +815,17 @@ fn print_crate_info( match expected_values { ExpectedValues::Any => check_cfgs.push(format!("{name}=any()")), ExpectedValues::Some(values) => { - check_cfgs.extend(values.iter().map(|value| { - if let Some(value) = value { - format!("{name}=\"{value}\"") - } else { - name.to_string() - } - })) + if !values.is_empty() { + check_cfgs.extend(values.iter().map(|value| { + if let Some(value) = value { + format!("{name}=\"{value}\"") + } else { + name.to_string() + } + })) + } else { + check_cfgs.push(format!("{name}=")) + } } } } @@ -1260,12 +1265,13 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto } fn parse_crate_attrs<'a>(sess: &'a Session) -> PResult<'a, ast::AttrVec> { - match &sess.io.input { - Input::File(ifile) => rustc_parse::parse_crate_attrs_from_file(ifile, &sess.psess), + let mut parser = unwrap_or_emit_fatal(match &sess.io.input { + Input::File(file) => new_parser_from_file(&sess.psess, file, None), Input::Str { name, input } => { - rustc_parse::parse_crate_attrs_from_source_str(name.clone(), input.clone(), &sess.psess) + new_parser_from_source_str(&sess.psess, name.clone(), input.clone()) } - } + }); + parser.parse_inner_attributes() } /// Runs a closure and catches unwinds triggered by fatal errors. diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 8acba57b7a6..31de0a747b2 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -3,7 +3,6 @@ use rustc_ast as ast; use rustc_ast_pretty::pprust as pprust_ast; use rustc_errors::FatalError; -use rustc_hir as hir; use rustc_hir_pretty as pprust_hir; use rustc_middle::bug; use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty}; @@ -70,11 +69,7 @@ struct HirIdentifiedAnn<'tcx> { impl<'tcx> pprust_hir::PpAnn for HirIdentifiedAnn<'tcx> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { - pprust_hir::PpAnn::nested( - &(&self.tcx.hir() as &dyn hir::intravisit::Map<'_>), - state, - nested, - ) + self.tcx.nested(state, nested) } fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { @@ -152,8 +147,7 @@ impl<'tcx> pprust_hir::PpAnn for HirTypedAnn<'tcx> { if let pprust_hir::Nested::Body(id) = nested { self.maybe_typeck_results.set(Some(self.tcx.typeck_body(id))); } - let pp_ann = &(&self.tcx.hir() as &dyn hir::intravisit::Map<'_>); - pprust_hir::PpAnn::nested(pp_ann, state, nested); + self.tcx.nested(state, nested); self.maybe_typeck_results.set(old_maybe_typeck_results); } diff --git a/compiler/rustc_error_codes/src/error_codes/E0582.md b/compiler/rustc_error_codes/src/error_codes/E0582.md index e50cc60ea33..b2cdb509c95 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0582.md +++ b/compiler/rustc_error_codes/src/error_codes/E0582.md @@ -27,6 +27,40 @@ fn bar<F, G>(t: F, u: G) fn main() { } ``` +This error also includes the use of associated types with lifetime parameters. +```compile_fail,E0582 +trait Foo { + type Assoc<'a>; +} + +struct Bar<X, F> +where + X: Foo, + F: for<'a> Fn(X::Assoc<'a>) -> &'a i32 +{ + x: X, + f: F +} +``` +The latter scenario encounters this error because `Foo::Assoc<'a>` could be +implemented by a type that does not use the `'a` parameter, so there is no +guarentee that `X::Assoc<'a>` actually uses `'a`. + +To fix this we can pass a dummy parameter: +``` +# trait Foo { +# type Assoc<'a>; +# } +struct Bar<X, F> +where + X: Foo, + F: for<'a> Fn(X::Assoc<'a>, /* dummy */ &'a ()) -> &'a i32 +{ + x: X, + f: F +} +``` + Note: The examples above used to be (erroneously) accepted by the compiler, but this was since corrected. See [issue #33685] for more details. diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index 530b37aadb1..2e150f7bb27 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -124,6 +124,9 @@ expand_not_a_meta_item = expand_only_one_word = must only be one word +expand_proc_macro_back_compat = using an old version of `{$crate_name}` + .note = older versions of the `{$crate_name}` crate no longer compile; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives + expand_proc_macro_derive_panicked = proc-macro derive panicked .help = message: {$message} @@ -154,7 +157,7 @@ expand_unsupported_key_value = key-value macro attributes are not supported expand_var_still_repeating = - variable '{$ident}' is still repeating at this depth + variable `{$ident}` is still repeating at this depth expand_wrong_fragment_kind = non-{$kind} macro in {$kind} position: {$name} diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 91af8758e51..b3f6a35f3a4 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -14,9 +14,8 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{DiagCtxt, ErrorGuaranteed, PResult}; use rustc_feature::Features; -use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; -use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, RegisteredTools}; -use rustc_parse::{parser, MACRO_ARGUMENTS}; +use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools}; +use rustc_parse::{parser::Parser, MACRO_ARGUMENTS}; use rustc_session::config::CollapseMacroDebuginfo; use rustc_session::{parse::ParseSess, Limit, Session}; use rustc_span::def_id::{CrateNum, DefId, LocalDefId}; @@ -1150,8 +1149,8 @@ impl<'a> ExtCtxt<'a> { pub fn monotonic_expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> { expand::MacroExpander::new(self, true) } - pub fn new_parser_from_tts(&self, stream: TokenStream) -> parser::Parser<'a> { - rustc_parse::stream_to_parser(&self.sess.psess, stream, MACRO_ARGUMENTS) + pub fn new_parser_from_tts(&self, stream: TokenStream) -> Parser<'a> { + Parser::new(&self.sess.psess, stream, MACRO_ARGUMENTS) } pub fn source_map(&self) -> &'a SourceMap { self.sess.psess.source_map() @@ -1330,80 +1329,63 @@ pub fn parse_macro_name_and_helper_attrs( Some((trait_ident.name, proc_attrs)) } -/// This nonterminal looks like some specific enums from -/// `proc-macro-hack` and `procedural-masquerade` crates. -/// We need to maintain some special pretty-printing behavior for them due to incorrect -/// asserts in old versions of those crates and their wide use in the ecosystem. -/// See issue #73345 for more details. +/// If this item looks like a specific enums from `rental`, emit a fatal error. +/// See #73345 and #83125 for more details. /// FIXME(#73933): Remove this eventually. -fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) -> bool { +fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) { let name = item.ident.name; - if name == sym::ProceduralMasqueradeDummyType { - if let ast::ItemKind::Enum(enum_def, _) = &item.kind { - if let [variant] = &*enum_def.variants { - if variant.ident.name == sym::Input { - let filename = sess.source_map().span_to_filename(item.ident.span); - if let FileName::Real(real) = filename { - if let Some(c) = real - .local_path() - .unwrap_or(Path::new("")) - .components() - .flat_map(|c| c.as_os_str().to_str()) - .find(|c| c.starts_with("rental") || c.starts_with("allsorts-rental")) - { - let crate_matches = if c.starts_with("allsorts-rental") { - true - } else { - let mut version = c.trim_start_matches("rental-").split('.'); - version.next() == Some("0") - && version.next() == Some("5") - && version - .next() - .and_then(|c| c.parse::<u32>().ok()) - .is_some_and(|v| v < 6) - }; - - if crate_matches { - sess.psess.buffer_lint( - PROC_MACRO_BACK_COMPAT, - item.ident.span, - ast::CRATE_NODE_ID, - BuiltinLintDiag::ProcMacroBackCompat { - crate_name: "rental".to_string(), - fixed_version: "0.5.6".to_string(), - }, - ); - return true; - } - } - } - } - } + if name == sym::ProceduralMasqueradeDummyType + && let ast::ItemKind::Enum(enum_def, _) = &item.kind + && let [variant] = &*enum_def.variants + && variant.ident.name == sym::Input + && let FileName::Real(real) = sess.source_map().span_to_filename(item.ident.span) + && let Some(c) = real + .local_path() + .unwrap_or(Path::new("")) + .components() + .flat_map(|c| c.as_os_str().to_str()) + .find(|c| c.starts_with("rental") || c.starts_with("allsorts-rental")) + { + let crate_matches = if c.starts_with("allsorts-rental") { + true + } else { + let mut version = c.trim_start_matches("rental-").split('.'); + version.next() == Some("0") + && version.next() == Some("5") + && version.next().and_then(|c| c.parse::<u32>().ok()).is_some_and(|v| v < 6) + }; + + if crate_matches { + // FIXME: make this translatable + #[allow(rustc::untranslatable_diagnostic)] + sess.psess.dcx.emit_fatal(errors::ProcMacroBackCompat { + crate_name: "rental".to_string(), + fixed_version: "0.5.6".to_string(), + }); } } - false } -pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &Session) -> bool { +pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &Session) { let item = match ann { Annotatable::Item(item) => item, Annotatable::Stmt(stmt) => match &stmt.kind { ast::StmtKind::Item(item) => item, - _ => return false, + _ => return, }, - _ => return false, + _ => return, }; pretty_printing_compatibility_hack(item, sess) } -pub(crate) fn nt_pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &Session) -> bool { +pub(crate) fn nt_pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &Session) { let item = match nt { Nonterminal::NtItem(item) => item, Nonterminal::NtStmt(stmt) => match &stmt.kind { ast::StmtKind::Item(item) => item, - _ => return false, + _ => return, }, - _ => return false, + _ => return, }; pretty_printing_compatibility_hack(item, sess) } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 1b6e191c2eb..37dfd830512 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -631,7 +631,10 @@ impl<'a> ExtCtxt<'a> { span, name, AttrVec::new(), - ast::ItemKind::Static(ast::StaticItem { ty, mutability, expr: Some(expr) }.into()), + ast::ItemKind::Static( + ast::StaticItem { ty, safety: ast::Safety::Default, mutability, expr: Some(expr) } + .into(), + ), ) } @@ -663,7 +666,7 @@ impl<'a> ExtCtxt<'a> { // Builds `#[name]`. pub fn attr_word(&self, name: Symbol, span: Span) -> ast::Attribute { let g = &self.sess.psess.attr_id_generator; - attr::mk_attr_word(g, ast::AttrStyle::Outer, name, span) + attr::mk_attr_word(g, ast::AttrStyle::Outer, ast::Safety::Default, name, span) } // Builds `#[name = val]`. @@ -671,12 +674,26 @@ impl<'a> ExtCtxt<'a> { // Note: `span` is used for both the identifier and the value. pub fn attr_name_value_str(&self, name: Symbol, val: Symbol, span: Span) -> ast::Attribute { let g = &self.sess.psess.attr_id_generator; - attr::mk_attr_name_value_str(g, ast::AttrStyle::Outer, name, val, span) + attr::mk_attr_name_value_str( + g, + ast::AttrStyle::Outer, + ast::Safety::Default, + name, + val, + span, + ) } // Builds `#[outer(inner)]`. pub fn attr_nested_word(&self, outer: Symbol, inner: Symbol, span: Span) -> ast::Attribute { let g = &self.sess.psess.attr_id_generator; - attr::mk_attr_nested_word(g, ast::AttrStyle::Outer, outer, inner, span) + attr::mk_attr_nested_word( + g, + ast::AttrStyle::Outer, + ast::Safety::Default, + outer, + inner, + span, + ) } } diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index a5fc9e9d89c..3f8b4661e5f 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -440,3 +440,13 @@ pub(crate) struct EmptyDelegationList { #[primary_span] pub span: Span, } + +// This used to be the `proc_macro_back_compat` lint (#83125). It was later +// turned into a hard error. +#[derive(Diagnostic)] +#[diag(expand_proc_macro_back_compat)] +#[note] +pub struct ProcMacroBackCompat { + pub crate_name: String, + pub fixed_version: String, +} diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index d8f0f221189..c28a09eb57c 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -778,7 +778,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { if let SyntaxExtensionKind::Derive(..) = ext { self.gate_proc_macro_input(&item); } - let meta = ast::MetaItem { kind: MetaItemKind::Word, span, path }; + // The `MetaItem` representing the trait to derive can't + // have an unsafe around it (as of now). + let meta = ast::MetaItem { + unsafety: ast::Safety::Default, + kind: MetaItemKind::Word, + span, + path, + }; let items = match expander.expand(self.cx, span, &meta, item, is_const) { ExpandResult::Ready(items) => items, ExpandResult::Retry(item) => { diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index e1f50876b05..25e961d6009 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -30,11 +30,11 @@ impl MutVisitor for Marker { // it's some advanced case with macro-generated macros. So if we cache the marked version // of that context once, we'll typically have a 100% cache hit rate after that. let Marker(expn_id, transparency, ref mut cache) = *self; - let data = span.data(); - let marked_ctxt = *cache - .entry(data.ctxt) - .or_insert_with(|| data.ctxt.apply_mark(expn_id.to_expn_id(), transparency)); - *span = data.with_ctxt(marked_ctxt); + span.update_ctxt(|ctxt| { + *cache + .entry(ctxt) + .or_insert_with(|| ctxt.apply_mark(expn_id.to_expn_id(), transparency)) + }); } } @@ -267,7 +267,6 @@ pub(super) fn transcribe<'a>( // some of the unnecessary whitespace. let ident = MacroRulesNormalizedIdent::new(original_ident); if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) { - // njn: explain the use of alone here let tt = match cur_matched { MatchedSingle(ParseNtResult::Tt(tt)) => { // `tt`s are emitted into the output stream directly as "raw tokens", diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index c8983619e70..506bd445be3 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -5,8 +5,8 @@ use crate::errors::{ use rustc_ast::ptr::P; use rustc_ast::{token, AttrVec, Attribute, Inline, Item, ModSpans}; use rustc_errors::{Diag, ErrorGuaranteed}; -use rustc_parse::new_parser_from_file; use rustc_parse::validate_attr; +use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use rustc_session::Session; use rustc_span::symbol::{sym, Ident}; @@ -66,7 +66,8 @@ pub(crate) fn parse_external_mod( } // Actually parse the external file as a module. - let mut parser = new_parser_from_file(&sess.psess, &mp.file_path, Some(span)); + let mut parser = + unwrap_or_emit_fatal(new_parser_from_file(&sess.psess, &mp.file_path, Some(span))); let (inner_attrs, items, inner_span) = parser.parse_mod(&token::Eof).map_err(|err| ModError::ParserError(err))?; attrs.extend(inner_attrs); diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index 530059e53c2..96145affe0a 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -4,14 +4,12 @@ use crate::proc_macro_server; use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; -use rustc_data_structures::sync::Lrc; use rustc_errors::ErrorGuaranteed; -use rustc_parse::parser::ForceCollect; +use rustc_parse::parser::{ForceCollect, Parser}; use rustc_session::config::ProcMacroExecutionStrategy; use rustc_span::profiling::SpannedEventArgRecorder; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; struct MessagePipe<T> { tx: std::sync::mpsc::SyncSender<T>, @@ -120,18 +118,13 @@ impl MultiItemModifier for DeriveProcMacro { // We need special handling for statement items // (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`) let is_stmt = matches!(item, Annotatable::Stmt(..)); - let hack = crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess); - let input = if hack { - let nt = match item { - Annotatable::Item(item) => token::NtItem(item), - Annotatable::Stmt(stmt) => token::NtStmt(stmt), - _ => unreachable!(), - }; - TokenStream::token_alone(token::Interpolated(Lrc::new(nt)), DUMMY_SP) - } else { - item.to_tokens() - }; + // We used to have an alternative behaviour for crates that needed it. + // We had a lint for a long time, but now we just emit a hard error. + // Eventually we might remove the special case hard error check + // altogether. See #73345. + crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess); + let input = item.to_tokens(); let stream = { let _timer = ecx.sess.prof.generic_activity_with_arg_recorder("expand_proc_macro", |recorder| { @@ -161,8 +154,7 @@ impl MultiItemModifier for DeriveProcMacro { }; let error_count_before = ecx.dcx().err_count(); - let mut parser = - rustc_parse::stream_to_parser(&ecx.sess.psess, stream, Some("proc-macro derive")); + let mut parser = Parser::new(&ecx.sess.psess, stream, Some("proc-macro derive")); let mut items = vec![]; loop { diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index ec7e4416b91..93f8682090d 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -13,7 +13,8 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diag, ErrorGuaranteed, MultiSpan, PResult}; use rustc_parse::lexer::nfc_normalize; -use rustc_parse::parse_stream_from_source_str; +use rustc_parse::parser::Parser; +use rustc_parse::{new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use rustc_span::def_id::CrateNum; use rustc_span::symbol::{self, sym, Symbol}; @@ -276,21 +277,20 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre Interpolated(nt) => { let stream = TokenStream::from_nonterminal_ast(&nt); - // A hack used to pass AST fragments to attribute and derive - // macros as a single nonterminal token instead of a token - // stream. Such token needs to be "unwrapped" and not - // represented as a delimited group. - // FIXME: It needs to be removed, but there are some - // compatibility issues (see #73345). - if crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.ecx.sess) { - trees.extend(Self::from_internal((stream, rustc))); - } else { - trees.push(TokenTree::Group(Group { - delimiter: pm::Delimiter::None, - stream: Some(stream), - span: DelimSpan::from_single(span), - })) - } + // We used to have an alternative behaviour for crates that + // needed it: a hack used to pass AST fragments to + // attribute and derive macros as a single nonterminal + // token instead of a token stream. Such token needs to be + // "unwrapped" and not represented as a delimited group. We + // had a lint for a long time, but now we just emit a hard + // error. Eventually we might remove the special case hard + // error check altogether. See #73345. + crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.ecx.sess); + trees.push(TokenTree::Group(Group { + delimiter: pm::Delimiter::None, + stream: Some(stream), + span: DelimSpan::from_single(span), + })) } OpenDelim(..) | CloseDelim(..) => unreachable!(), @@ -467,7 +467,8 @@ impl server::FreeFunctions for Rustc<'_, '_> { fn literal_from_str(&mut self, s: &str) -> Result<Literal<Self::Span, Self::Symbol>, ()> { let name = FileName::proc_macro_source_code(s); - let mut parser = rustc_parse::new_parser_from_source_str(self.psess(), name, s.to_owned()); + let mut parser = + unwrap_or_emit_fatal(new_parser_from_source_str(self.psess(), name, s.to_owned())); let first_span = parser.token.span.data(); let minus_present = parser.eat(&token::BinOp(token::Minus)); @@ -539,12 +540,12 @@ impl server::TokenStream for Rustc<'_, '_> { } fn from_str(&mut self, src: &str) -> Self::TokenStream { - parse_stream_from_source_str( + unwrap_or_emit_fatal(source_str_to_stream( + self.psess(), FileName::proc_macro_source_code(src), src.to_string(), - self.psess(), Some(self.call_site), - ) + )) } fn to_string(&mut self, stream: &Self::TokenStream) -> String { @@ -554,11 +555,7 @@ impl server::TokenStream for Rustc<'_, '_> { fn expand_expr(&mut self, stream: &Self::TokenStream) -> Result<Self::TokenStream, ()> { // Parse the expression from our tokenstream. let expr: PResult<'_, _> = try { - let mut p = rustc_parse::stream_to_parser( - self.psess(), - stream.clone(), - Some("proc_macro expand expr"), - ); + let mut p = Parser::new(self.psess(), stream.clone(), Some("proc_macro expand expr")); let expr = p.parse_expr()?; if p.token != token::Eof { p.unexpected()?; diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 8b7e93fd555..9b5e4e50d3c 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -59,6 +59,16 @@ pub enum AttributeType { CrateLevel, } +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum AttributeSafety { + /// Normal attribute that does not need `#[unsafe(...)]` + Normal, + + /// Unsafe attribute that requires safety obligations + /// to be discharged + Unsafe, +} + #[derive(Clone, Copy)] pub enum AttributeGate { /// Is gated by a given feature gate, reason @@ -172,11 +182,23 @@ macro_rules! template { } macro_rules! ungated { + (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => { + BuiltinAttribute { + name: sym::$attr, + encode_cross_crate: $encode_cross_crate, + type_: $typ, + safety: AttributeSafety::Unsafe, + template: $tpl, + gate: Ungated, + duplicates: $duplicates, + } + }; ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, + safety: AttributeSafety::Normal, template: $tpl, gate: Ungated, duplicates: $duplicates, @@ -185,11 +207,34 @@ macro_rules! ungated { } macro_rules! gated { + (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => { + BuiltinAttribute { + name: sym::$attr, + encode_cross_crate: $encode_cross_crate, + type_: $typ, + safety: AttributeSafety::Unsafe, + template: $tpl, + duplicates: $duplicates, + gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)), + } + }; + (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => { + BuiltinAttribute { + name: sym::$attr, + encode_cross_crate: $encode_cross_crate, + type_: $typ, + safety: AttributeSafety::Unsafe, + template: $tpl, + duplicates: $duplicates, + gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)), + } + }; ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, + safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)), @@ -200,6 +245,7 @@ macro_rules! gated { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, + safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)), @@ -228,6 +274,7 @@ macro_rules! rustc_attr { name: sym::$attr, encode_cross_crate: $encode_cross_crate, type_: $typ, + safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)), @@ -258,6 +305,7 @@ pub struct BuiltinAttribute { /// Otherwise, it can only be used in the local crate. pub encode_cross_crate: EncodeCrossCrate, pub type_: AttributeType, + pub safety: AttributeSafety, pub template: AttributeTemplate, pub duplicates: AttributeDuplicates, pub gate: AttributeGate, @@ -375,9 +423,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No), - ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), - ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), - ungated!(no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), + ungated!(unsafe export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), + ungated!(unsafe link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No), + ungated!(unsafe no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No), ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes), @@ -486,11 +534,11 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), gated!( - ffi_pure, Normal, template!(Word), WarnFollowing, + unsafe ffi_pure, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, experimental!(ffi_pure) ), gated!( - ffi_const, Normal, template!(Word), WarnFollowing, + unsafe ffi_const, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, experimental!(ffi_const) ), gated!( @@ -850,6 +898,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`. encode_cross_crate: EncodeCrossCrate::Yes, type_: Normal, + safety: AttributeSafety::Normal, template: template!(NameValueStr: "name"), duplicates: ErrorFollowing, gate: Gated( @@ -1096,6 +1145,10 @@ pub fn is_valid_for_get_attr(name: Symbol) -> bool { }) } +pub fn is_unsafe_attr(name: Symbol) -> bool { + BUILTIN_ATTRIBUTE_MAP.get(&name).is_some_and(|attr| attr.safety == AttributeSafety::Unsafe) +} + pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> = LazyLock::new(|| { let mut map = FxHashMap::default(); diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 9cbf836ec76..9db9073e2f0 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -123,8 +123,8 @@ pub use accepted::ACCEPTED_FEATURES; pub use builtin_attrs::AttributeDuplicates; pub use builtin_attrs::{ deprecated_attributes, encode_cross_crate, find_gated_cfg, is_builtin_attr_name, - is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType, BuiltinAttribute, - GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, + is_unsafe_attr, is_valid_for_get_attr, AttributeGate, AttributeTemplate, AttributeType, + BuiltinAttribute, GatedCfg, BUILTIN_ATTRIBUTES, BUILTIN_ATTRIBUTE_MAP, }; pub use removed::REMOVED_FEATURES; pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_FEATURES}; diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index eaaf7ca34e0..aea447b2aff 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -128,6 +128,8 @@ declare_features! ( /// Allows the use of type alias impl trait in function return positions (removed, min_type_alias_impl_trait, "1.56.0", Some(63063), Some("removed in favor of full type_alias_impl_trait")), + /// Make `mut` not reset the binding mode on edition >= 2024. + (removed, mut_preserve_binding_mode_2024, "1.79.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024`")), (removed, needs_allocator, "1.4.0", Some(27389), Some("subsumed by `#![feature(allocator_internals)]`")), /// Allows use of unary negate on unsigned integers, e.g., -e for e: u8 @@ -181,6 +183,7 @@ declare_features! ( (removed, pushpop_unsafe, "1.2.0", None, None), (removed, quad_precision_float, "1.0.0", None, None), (removed, quote, "1.33.0", Some(29601), None), + (removed, ref_pat_everywhere, "1.79.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024")), (removed, reflect, "1.0.0", Some(27749), None), /// Allows using the `#[register_attr]` attribute. (removed, register_attr, "1.65.0", Some(66080), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 2a4859a2478..2410019868a 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -177,8 +177,6 @@ declare_features! ( /// Allows using the `unadjusted` ABI; perma-unstable. (internal, abi_unadjusted, "1.16.0", None), - /// Allows using the `vectorcall` ABI. - (unstable, abi_vectorcall, "1.7.0", None), /// Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`. (internal, allocator_internals, "1.20.0", None), /// Allows using `#[allow_internal_unsafe]`. This is an @@ -243,6 +241,8 @@ declare_features! ( // feature-group-start: internal feature gates // ------------------------------------------------------------------------- + /// Allows using the `vectorcall` ABI. + (unstable, abi_vectorcall, "1.7.0", Some(124485)), /// Allows features specific to auto traits. /// Renamed from `optin_builtin_traits`. (unstable, auto_traits, "1.50.0", Some(13231)), @@ -529,8 +529,6 @@ declare_features! ( (unstable, more_qualified_paths, "1.54.0", Some(86935)), /// Allows the `#[must_not_suspend]` attribute. (unstable, must_not_suspend, "1.57.0", Some(83310)), - /// Make `mut` not reset the binding mode on edition >= 2024. - (incomplete, mut_preserve_binding_mode_2024, "1.79.0", Some(123076)), /// Allows `mut ref` and `mut ref mut` identifier patterns. (incomplete, mut_ref, "1.79.0", Some(123076)), /// Allows using `#[naked]` on functions. @@ -561,6 +559,8 @@ declare_features! ( (unstable, offset_of_enum, "1.75.0", Some(120141)), /// Allows using multiple nested field accesses in offset_of! (unstable, offset_of_nested, "1.77.0", Some(120140)), + /// Allows using fields with slice type in offset_of! + (unstable, offset_of_slice, "CURRENT_RUSTC_VERSION", Some(126151)), /// Allows using `#[optimize(X)]`. (unstable, optimize_attribute, "1.34.0", Some(54882)), /// Allows postfix match `expr.match { ... }` @@ -573,8 +573,6 @@ declare_features! ( (unstable, raw_ref_op, "1.41.0", Some(64490)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)), - /// Allows `&` and `&mut` patterns to consume match-ergonomics-inserted references. - (incomplete, ref_pat_everywhere, "1.79.0", Some(123076)), /// Allows using the `#[register_tool]` attribute. (unstable, register_tool, "1.41.0", Some(66079)), /// Allows the `#[repr(i128)]` attribute for enums. @@ -624,6 +622,10 @@ declare_features! ( (unstable, type_changing_struct_update, "1.58.0", Some(86555)), /// Allows unnamed fields of struct and union type (incomplete, unnamed_fields, "1.74.0", Some(49804)), + /// Allows unsafe attributes. + (unstable, unsafe_attributes, "CURRENT_RUSTC_VERSION", Some(123757)), + /// Allows unsafe on extern declarations and safety qualifiers over internal items. + (unstable, unsafe_extern_blocks, "CURRENT_RUSTC_VERSION", Some(123743)), /// Allows unsized fn parameters. (unstable, unsized_fn_params, "1.49.0", Some(48055)), /// Allows unsized rvalues at arguments and parameters. diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 649a08b6972..b1854923247 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -76,6 +76,8 @@ pub enum DefKind { /// Constant generic parameter: `struct Foo<const N: usize> { ... }` ConstParam, Static { + /// Whether it's a `unsafe static`, `safe static` (inside extern only) or just a `static`. + safety: hir::Safety, /// Whether it's a `static mut` or just a `static`. mutability: ast::Mutability, /// Whether it's an anonymous static generated for nested allocations. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index e971d0e3c14..87ff39a8294 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -907,9 +907,6 @@ pub struct OwnerNodes<'tcx> { pub nodes: IndexVec<ItemLocalId, ParentedNode<'tcx>>, /// Content of local bodies. pub bodies: SortedMap<ItemLocalId, &'tcx Body<'tcx>>, - /// Whether the body contains inline constants that are created for the query system during typeck - /// of the body. - pub has_inline_consts: bool, } impl<'tcx> OwnerNodes<'tcx> { @@ -1626,6 +1623,14 @@ pub struct AnonConst { pub span: Span, } +/// An inline constant expression `const { something }`. +#[derive(Copy, Clone, Debug, HashStable_Generic)] +pub struct ConstBlock { + pub hir_id: HirId, + pub def_id: LocalDefId, + pub body: BodyId, +} + /// An expression. #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Expr<'hir> { @@ -1912,7 +1917,7 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum ExprKind<'hir> { /// Allow anonymous constants from an inline `const` block - ConstBlock(&'hir Expr<'hir>), + ConstBlock(ConstBlock), /// An array (e.g., `[a, b, c, d]`). Array(&'hir [Expr<'hir>]), /// A function call. @@ -2345,7 +2350,9 @@ impl ImplItemId { } } -/// Represents anything within an `impl` block. +/// Represents an associated item within an impl block. +/// +/// Refer to [`Impl`] for an impl block declaration. #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct ImplItem<'hir> { pub ident: Ident, @@ -3327,6 +3334,10 @@ pub enum ItemKind<'hir> { Impl(&'hir Impl<'hir>), } +/// Represents an impl block declaration. +/// +/// E.g., `impl $Type { .. }` or `impl $Trait for $Type { .. }` +/// Refer to [`ImplItem`] for an associated item within an impl block. #[derive(Debug, Clone, Copy, HashStable_Generic)] pub struct Impl<'hir> { pub safety: Safety, @@ -3475,9 +3486,9 @@ impl ForeignItem<'_> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum ForeignItemKind<'hir> { /// A foreign function. - Fn(&'hir FnDecl<'hir>, &'hir [Ident], &'hir Generics<'hir>), + Fn(&'hir FnDecl<'hir>, &'hir [Ident], &'hir Generics<'hir>, Safety), /// A foreign static item (`static ext: u8`). - Static(&'hir Ty<'hir>, Mutability), + Static(&'hir Ty<'hir>, Mutability, Safety), /// A foreign type. Type, } @@ -3545,7 +3556,7 @@ impl<'hir> OwnerNode<'hir> { | OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) | OwnerNode::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig.decl), OwnerNode::ForeignItem(ForeignItem { - kind: ForeignItemKind::Fn(fn_decl, _, _), + kind: ForeignItemKind::Fn(fn_decl, _, _, _), .. }) => Some(fn_decl), _ => None, @@ -3644,6 +3655,7 @@ pub enum Node<'hir> { Variant(&'hir Variant<'hir>), Field(&'hir FieldDef<'hir>), AnonConst(&'hir AnonConst), + ConstBlock(&'hir ConstBlock), Expr(&'hir Expr<'hir>), ExprField(&'hir ExprField<'hir>), Stmt(&'hir Stmt<'hir>), @@ -3704,6 +3716,7 @@ impl<'hir> Node<'hir> { Node::PreciseCapturingNonLifetimeArg(a) => Some(a.ident), Node::Param(..) | Node::AnonConst(..) + | Node::ConstBlock(..) | Node::Expr(..) | Node::Stmt(..) | Node::Block(..) @@ -3728,9 +3741,9 @@ impl<'hir> Node<'hir> { | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. }) | Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig.decl), Node::Expr(Expr { kind: ExprKind::Closure(Closure { fn_decl, .. }), .. }) - | Node::ForeignItem(ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => { - Some(fn_decl) - } + | Node::ForeignItem(ForeignItem { + kind: ForeignItemKind::Fn(fn_decl, _, _, _), .. + }) => Some(fn_decl), _ => None, } } @@ -3801,6 +3814,7 @@ impl<'hir> Node<'hir> { } Node::AnonConst(constant) => Some((constant.def_id, constant.body)), + Node::ConstBlock(constant) => Some((constant.def_id, constant.body)), _ => None, } @@ -3813,7 +3827,7 @@ impl<'hir> Node<'hir> { pub fn generics(self) -> Option<&'hir Generics<'hir>> { match self { Node::ForeignItem(ForeignItem { - kind: ForeignItemKind::Fn(_, _, generics), .. + kind: ForeignItemKind::Fn(_, _, generics, _), .. }) | Node::TraitItem(TraitItem { generics, .. }) | Node::ImplItem(ImplItem { generics, .. }) => Some(generics), @@ -3869,6 +3883,7 @@ impl<'hir> Node<'hir> { expect_variant, &'hir Variant<'hir>, Node::Variant(n), n; expect_field, &'hir FieldDef<'hir>, Node::Field(n), n; expect_anon_const, &'hir AnonConst, Node::AnonConst(n), n; + expect_inline_const, &'hir ConstBlock, Node::ConstBlock(n), n; expect_expr, &'hir Expr<'hir>, Node::Expr(n), n; expect_expr_field, &'hir ExprField<'hir>, Node::ExprField(n), n; expect_stmt, &'hir Stmt<'hir>, Node::Stmt(n), n; diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 9bc2bbe0c64..5a16f266dab 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -344,6 +344,9 @@ pub trait Visitor<'v>: Sized { fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result { walk_anon_const(self, c) } + fn visit_inline_const(&mut self, c: &'v ConstBlock) -> Self::Result { + walk_inline_const(self, c) + } fn visit_expr(&mut self, ex: &'v Expr<'v>) -> Self::Result { walk_expr(self, ex) } @@ -608,12 +611,14 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>( try_visit!(visitor.visit_ident(foreign_item.ident)); match foreign_item.kind { - ForeignItemKind::Fn(ref function_declaration, param_names, ref generics) => { + ForeignItemKind::Fn(ref function_declaration, param_names, ref generics, _) => { try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_fn_decl(function_declaration)); walk_list!(visitor, visit_ident, param_names.iter().copied()); } - ForeignItemKind::Static(ref typ, _) => try_visit!(visitor.visit_ty(typ)), + ForeignItemKind::Static(ref typ, _, _) => { + try_visit!(visitor.visit_ty(typ)); + } ForeignItemKind::Type => (), } V::Result::output() @@ -716,6 +721,14 @@ pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonCo visitor.visit_nested_body(constant.body) } +pub fn walk_inline_const<'v, V: Visitor<'v>>( + visitor: &mut V, + constant: &'v ConstBlock, +) -> V::Result { + try_visit!(visitor.visit_id(constant.hir_id)); + visitor.visit_nested_body(constant.body) +} + pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) -> V::Result { try_visit!(visitor.visit_id(expression.hir_id)); match expression.kind { @@ -723,7 +736,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) walk_list!(visitor, visit_expr, subexpressions); } ExprKind::ConstBlock(ref const_block) => { - try_visit!(visitor.visit_expr(const_block)) + try_visit!(visitor.visit_inline_const(const_block)) } ExprKind::Repeat(ref element, ref count) => { try_visit!(visitor.visit_expr(element)); diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 1ebd4b80e18..baa1635f731 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -93,8 +93,7 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<' // `local_id_to_def_id` is also ignored because is dependent on the body, then just hashing // the body satisfies the condition of two nodes being different have different // `hash_stable` results. - let OwnerNodes { opt_hash_including_bodies, nodes: _, bodies: _, has_inline_consts: _ } = - *self; + let OwnerNodes { opt_hash_including_bodies, nodes: _, bodies: _ } = *self; opt_hash_including_bodies.unwrap().hash_stable(hcx, hasher); } } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 3904f14b0f6..72e5995e892 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -15,6 +15,7 @@ use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; use rustc_middle::middle::stability::EvalResult; use rustc_middle::span_bug; +use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt}; @@ -342,7 +343,7 @@ fn check_opaque_meets_bounds<'tcx>( let param_env = tcx.param_env(defining_use_anchor); let infcx = tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let args = match *origin { hir::OpaqueTyOrigin::FnReturn(parent) @@ -801,7 +802,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { let item = tcx.hir().foreign_item(item.id); match &item.kind { - hir::ForeignItemKind::Fn(fn_decl, _, _) => { + hir::ForeignItemKind::Fn(fn_decl, _, _, _) => { require_c_abi_if_c_variadic(tcx, fn_decl, abi, item.span); } hir::ForeignItemKind::Static(..) => { @@ -1727,7 +1728,7 @@ pub(super) fn check_coroutine_obligations( .with_opaque_type_inference(def_id) .build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); for (predicate, cause) in &typeck_results.coroutine_stalled_predicates { ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, *predicate)); } 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 db749ef3f81..82b57cdd106 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -10,7 +10,7 @@ use rustc_hir::intravisit; use rustc_hir::{GenericParamKind, ImplItemKind}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::{util, FulfillmentError}; +use rustc_infer::traits::util; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::util::ExplicitSelf; @@ -25,7 +25,7 @@ use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{ - self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, + self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, }; use std::borrow::Cow; use std::iter; @@ -225,7 +225,7 @@ fn compare_method_predicate_entailment<'tcx>( let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); let infcx = &tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); debug!("compare_impl_method: caller_bounds={:?}", param_env.caller_bounds()); @@ -493,7 +493,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( ); let infcx = &tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); // Normalize the impl signature with fresh variables for lifetime inference. let misc_cause = ObligationCause::misc(return_span, impl_m_def_id); @@ -764,17 +764,20 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( Ok(&*tcx.arena.alloc(remapped_types)) } -struct ImplTraitInTraitCollector<'a, 'tcx> { - ocx: &'a ObligationCtxt<'a, 'tcx>, +struct ImplTraitInTraitCollector<'a, 'tcx, E> { + ocx: &'a ObligationCtxt<'a, 'tcx, E>, types: FxIndexMap<DefId, (Ty<'tcx>, ty::GenericArgsRef<'tcx>)>, span: Span, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, } -impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> { +impl<'a, 'tcx, E> ImplTraitInTraitCollector<'a, 'tcx, E> +where + E: 'tcx, +{ fn new( - ocx: &'a ObligationCtxt<'a, 'tcx>, + ocx: &'a ObligationCtxt<'a, 'tcx, E>, span: Span, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, @@ -783,7 +786,10 @@ impl<'a, 'tcx> ImplTraitInTraitCollector<'a, 'tcx> { } } -impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> { +impl<'tcx, E> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx, E> +where + E: 'tcx, +{ fn interner(&self) -> TyCtxt<'tcx> { self.ocx.infcx.tcx } @@ -1777,7 +1783,7 @@ fn compare_const_predicate_entailment<'tcx>( ); let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let impl_ct_own_bounds = impl_ct_predicates.instantiate_own(tcx, impl_args); for (predicate, span) in impl_ct_own_bounds { @@ -1910,7 +1916,7 @@ fn compare_type_predicate_entailment<'tcx>( let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause); let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); debug!("compare_type_predicate_entailment: caller_bounds={:?}", param_env.caller_bounds()); @@ -1977,7 +1983,7 @@ pub(super) fn check_type_bounds<'tcx>( let rebased_args = impl_ty_args.rebase_onto(tcx, container_id, impl_trait_ref.args); let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); // A synthetic impl Trait for RPITIT desugaring has no HIR, which we currently use to get the // span for an impl's associated type. Instead, for these, use the def_span for the synthesized @@ -2192,9 +2198,6 @@ fn param_env_with_gat_bounds<'tcx>( tcx, ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1), - tcx.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), ) .into() } @@ -2275,7 +2278,7 @@ fn try_report_async_mismatch<'tcx>( && let Some(proj) = proj.no_bound_vars() && infcx.can_eq( error.root_obligation.param_env, - proj.term.ty().unwrap(), + proj.term.expect_type(), impl_sig.output(), ) { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index ca08eeea227..10b097a1060 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -267,7 +267,7 @@ fn report_mismatched_rpitit_signature<'tcx>( .explicit_item_bounds(future_ty.def_id) .iter_instantiated_copied(tcx, future_ty.args) .find_map(|(clause, _)| match clause.kind().no_bound_vars()? { - ty::ClauseKind::Projection(proj) => proj.term.ty(), + ty::ClauseKind::Projection(proj) => proj.term.as_type(), _ => None, }) else { diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index be412dde968..8ec6dd12a78 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -123,7 +123,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( adt_to_impl_args: GenericArgsRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); // Take the param-env of the adt and instantiate the args that show up in // the implementation's self type. This gives us the assumptions that the diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 25ac31c16c7..cc52a765802 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -133,7 +133,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { main_diagnostics_def_id, ObligationCauseCode::MainFunctionType, ); - let ocx = traits::ObligationCtxt::new(&infcx); + let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); let norm_return_ty = ocx.normalize(&cause, param_env, return_ty); ocx.register_bound(cause, param_env, norm_return_ty, term_did); let errors = ocx.select_all_or_error(); diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs index a49626eed35..2cdcc06f53c 100644 --- a/compiler/rustc_hir_analysis/src/check/errs.rs +++ b/compiler/rustc_hir_analysis/src/check/errs.rs @@ -41,7 +41,8 @@ fn path_if_static_mut(tcx: TyCtxt<'_>, expr: &hir::Expr<'_>) -> Option<String> { if let hir::ExprKind::Path(qpath) = expr.kind && let hir::QPath::Resolved(_, path) = qpath && let hir::def::Res::Def(def_kind, _) = path.res - && let hir::def::DefKind::Static { mutability: Mutability::Mut, nested: false } = def_kind + && let hir::def::DefKind::Static { safety: _, mutability: Mutability::Mut, nested: false } = + def_kind { return Some(qpath_to_string(&tcx, &qpath)); } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index f7989aeab41..13180fa2673 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -29,7 +29,7 @@ fn equate_intrinsic_type<'tcx>( let (own_counts, span) = match tcx.hir_node_by_def_id(def_id) { hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }) | hir::Node::ForeignItem(hir::ForeignItem { - kind: hir::ForeignItemKind::Fn(.., generics), + kind: hir::ForeignItemKind::Fn(.., generics, _), .. }) => { let own_counts = tcx.generics_of(def_id).own_counts(); diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 149e7737e30..4d1b96d9c1b 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -441,7 +441,9 @@ fn fn_sig_suggestion<'tcx>( output = if let ty::Alias(_, alias_ty) = *output.kind() { tcx.explicit_item_super_predicates(alias_ty.def_id) .iter_instantiated_copied(tcx, alias_ty.args) - .find_map(|(bound, _)| bound.as_projection_clause()?.no_bound_vars()?.term.ty()) + .find_map(|(bound, _)| { + bound.as_projection_clause()?.no_bound_vars()?.term.as_type() + }) .unwrap_or_else(|| { span_bug!( ident.span, @@ -599,7 +601,7 @@ pub fn check_function_signature<'tcx>( let param_env = ty::ParamEnv::empty(); let infcx = &tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); let actual_sig = tcx.fn_sig(fn_id).instantiate_identity(); diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 30b03b43872..72e431926ca 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -407,14 +407,11 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h match expr.kind { // Manually recurse over closures and inline consts, because they are the only // case of nested bodies that share the parent environment. - hir::ExprKind::Closure(&hir::Closure { body, .. }) => { + hir::ExprKind::Closure(&hir::Closure { body, .. }) + | hir::ExprKind::ConstBlock(hir::ConstBlock { body, .. }) => { let body = visitor.tcx.hir().body(body); visitor.visit_body(body); } - hir::ExprKind::ConstBlock(expr) => visitor.enter_body(expr.hir_id, |this| { - this.cx.var_parent = None; - resolve_local(this, None, Some(expr)); - }), hir::ExprKind::AssignOp(_, left_expr, right_expr) => { debug!( "resolve_expr - enabling pessimistic_yield, was previously {}", diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 81e3d8c7ece..b206d8046ee 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -37,7 +37,7 @@ use rustc_trait_selection::traits::misc::{ use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{ - self, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, + self, FulfillmentError, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, }; use rustc_type_ir::TypeFlags; @@ -45,13 +45,13 @@ use std::cell::LazyCell; use std::ops::{ControlFlow, Deref}; pub(super) struct WfCheckingCtxt<'a, 'tcx> { - pub(super) ocx: ObligationCtxt<'a, 'tcx>, + pub(super) ocx: ObligationCtxt<'a, 'tcx, FulfillmentError<'tcx>>, span: Span, body_def_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, } impl<'a, 'tcx> Deref for WfCheckingCtxt<'a, 'tcx> { - type Target = ObligationCtxt<'a, 'tcx>; + type Target = ObligationCtxt<'a, 'tcx, FulfillmentError<'tcx>>; fn deref(&self) -> &Self::Target { &self.ocx } @@ -106,7 +106,7 @@ where { let param_env = tcx.param_env(body_def_id); let infcx = &tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); let mut wfcx = WfCheckingCtxt { ocx, span, body_def_id, param_env }; @@ -881,7 +881,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem _ => {} } if !trait_should_be_self.is_empty() { - if tcx.check_is_object_safe(trait_def_id) { + if tcx.is_object_safe(trait_def_id) { return; } let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect(); diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 84771978a46..61adb7a3cba 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -267,7 +267,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() .join(", "), })); } else { - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); for field in coerced_fields { ocx.register_obligation(Obligation::new( tcx, @@ -480,7 +480,7 @@ pub fn coerce_unsized_info<'tcx>( }; // Register an obligation for `A: Trait<B>`. - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let cause = traits::ObligationCause::misc(span, impl_did); let obligation = Obligation::new( tcx, diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 480318acca8..eae41d28e89 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -191,7 +191,7 @@ fn check_object_overlap<'tcx>( }); for component_def_id in component_def_ids { - if !tcx.check_is_object_safe(component_def_id) { + if !tcx.is_object_safe(component_def_id) { // Without the 'object_safe_for_dispatch' feature this is an error // which will be reported by wfcheck. Ignore it here. // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`. diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index bdac0d9b0b4..61ac4af0151 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -14,7 +14,6 @@ use rustc_middle::{bug, span_bug}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_trait_selection::traits::{self, IsFirstInputType, UncoveredTyParams}; use rustc_trait_selection::traits::{OrphanCheckErr, OrphanCheckMode}; -use rustc_trait_selection::traits::{StructurallyNormalizeExt, TraitEngineExt}; #[instrument(level = "debug", skip(tcx))] pub(crate) fn orphan_check_impl( @@ -317,12 +316,12 @@ fn orphan_check<'tcx>( } let ty = if infcx.next_trait_solver() { - let mut fulfill_cx = <dyn traits::TraitEngine<'_>>::new(&infcx); - infcx - .at(&cause, ty::ParamEnv::empty()) - .structurally_normalize(ty, &mut *fulfill_cx) - .map(|ty| infcx.resolve_vars_if_possible(ty)) - .unwrap_or(ty) + ocx.structurally_normalize( + &cause, + ty::ParamEnv::empty(), + infcx.resolve_vars_if_possible(ty), + ) + .unwrap_or(ty) } else { ty }; diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 7e746006148..c6e8759327f 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -18,11 +18,11 @@ use rustc_ast::Recovered; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordMap; -use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey}; -use rustc_hir as hir; +use rustc_errors::{struct_span_code_err, Applicability, Diag, ErrorGuaranteed, StashKey, E0228}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{self, Visitor}; +use rustc_hir::intravisit::{self, walk_generics, Visitor}; +use rustc_hir::{self as hir}; use rustc_hir::{GenericParamKind, Node}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; @@ -44,7 +44,7 @@ use std::ops::Bound; use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::errors; -use crate::hir_ty_lowering::HirTyLowerer; +use crate::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; pub use type_of::test_opaque_hidden_types; mod generics_of; @@ -370,32 +370,34 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { self.tcx } - fn item_def_id(&self) -> DefId { - self.item_def_id.to_def_id() + fn item_def_id(&self) -> LocalDefId { + self.item_def_id } - fn allow_infer(&self) -> bool { - false - } - - fn re_infer(&self, _: Option<&ty::GenericParamDef>, _: Span) -> Option<ty::Region<'tcx>> { - None + fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> { + if let RegionInferReason::BorrowedObjectLifetimeDefault = reason { + let e = struct_span_code_err!( + self.tcx().dcx(), + span, + E0228, + "the lifetime bound for this object type cannot be deduced \ + from context; please supply an explicit bound" + ) + .emit(); + self.set_tainted_by_errors(e); + ty::Region::new_error(self.tcx(), e) + } else { + // This indicates an illegal lifetime in a non-assoc-trait position + ty::Region::new_error_with_message(self.tcx(), span, "unelided lifetime in signature") + } } fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { Ty::new_error_with_message(self.tcx(), span, "bad placeholder type") } - fn ct_infer(&self, ty: Ty<'tcx>, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> { - let ty = self.tcx.fold_regions(ty, |r, _| match *r { - rustc_type_ir::RegionKind::ReStatic => r, - - // This is never reached in practice. If it ever is reached, - // `ReErased` should be changed to `ReStatic`, and any other region - // left alone. - r => bug!("unexpected region: {r:?}"), - }); - ty::Const::new_error_with_message(self.tcx(), ty, span, "bad placeholder constant") + fn ct_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> { + ty::Const::new_error_with_message(self.tcx(), span, "bad placeholder constant") } fn probe_ty_param_bounds( @@ -510,6 +512,89 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { fn set_tainted_by_errors(&self, err: ErrorGuaranteed) { self.tainted_by_errors.set(Some(err)); } + + fn lower_fn_sig( + &self, + decl: &hir::FnDecl<'tcx>, + generics: Option<&hir::Generics<'_>>, + hir_id: rustc_hir::HirId, + hir_ty: Option<&hir::Ty<'_>>, + ) -> (Vec<Ty<'tcx>>, Ty<'tcx>) { + let tcx = self.tcx(); + // We proactively collect all the inferred type params to emit a single error per fn def. + let mut visitor = HirPlaceholderCollector::default(); + let mut infer_replacements = vec![]; + + if let Some(generics) = generics { + walk_generics(&mut visitor, generics); + } + + let input_tys = decl + .inputs + .iter() + .enumerate() + .map(|(i, a)| { + if let hir::TyKind::Infer = a.kind { + if let Some(suggested_ty) = + self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i)) + { + infer_replacements.push((a.span, suggested_ty.to_string())); + return Ty::new_error_with_message(tcx, a.span, suggested_ty.to_string()); + } + } + + // Only visit the type looking for `_` if we didn't fix the type above + visitor.visit_ty(a); + self.lowerer().lower_arg_ty(a, None) + }) + .collect(); + + let output_ty = match decl.output { + hir::FnRetTy::Return(output) => { + if let hir::TyKind::Infer = output.kind + && let Some(suggested_ty) = + self.lowerer().suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None) + { + infer_replacements.push((output.span, suggested_ty.to_string())); + Ty::new_error_with_message(tcx, output.span, suggested_ty.to_string()) + } else { + visitor.visit_ty(output); + self.lower_ty(output) + } + } + hir::FnRetTy::DefaultReturn(..) => tcx.types.unit, + }; + + if !(visitor.0.is_empty() && infer_replacements.is_empty()) { + // We check for the presence of + // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`. + + let mut diag = crate::collect::placeholder_type_error_diag( + tcx, + generics, + visitor.0, + infer_replacements.iter().map(|(s, _)| *s).collect(), + true, + hir_ty, + "function", + ); + + if !infer_replacements.is_empty() { + diag.multipart_suggestion( + format!( + "try replacing `_` with the type{} in the corresponding trait method signature", + rustc_errors::pluralize!(infer_replacements.len()), + ), + infer_replacements, + Applicability::MachineApplicable, + ); + } + + self.set_tainted_by_errors(diag.emit()); + } + + (input_tys, output_ty) + } } /// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present. @@ -1321,9 +1406,11 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn icx.lowerer().lower_fn_ty(hir_id, header.safety, header.abi, decl, Some(generics), None) } - ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => { + ForeignItem(&hir::ForeignItem { + kind: ForeignItemKind::Fn(fn_decl, _, _, safety), .. + }) => { let abi = tcx.hir().get_foreign_abi(hir_id); - compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi) + compute_sig_of_foreign_fn_decl(tcx, def_id, fn_decl, abi, safety) } Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => { @@ -1695,11 +1782,12 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( def_id: LocalDefId, decl: &'tcx hir::FnDecl<'tcx>, abi: abi::Abi, + safety: hir::Safety, ) -> ty::PolyFnSig<'tcx> { let safety = if abi == abi::Abi::RustIntrinsic { intrinsic_operation_unsafety(tcx, def_id) } else { - hir::Safety::Unsafe + safety }; let hir_id = tcx.local_def_id_to_hir_id(def_id); let fty = diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 9af959681fb..abdf85ad707 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -177,10 +177,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } } } - Node::Expr(&hir::Expr { - kind: hir::ExprKind::Closure { .. } | hir::ExprKind::ConstBlock { .. }, - .. - }) => Some(tcx.typeck_root_def_id(def_id.to_def_id())), + Node::ConstBlock(_) + | Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => { + Some(tcx.typeck_root_def_id(def_id.to_def_id())) + } Node::Item(item) => match item.kind { ItemKind::OpaqueTy(&hir::OpaqueTy { origin: @@ -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::Expr(Expr { kind: ExprKind::ConstBlock(..), .. }) = node { + if let Node::ConstBlock(_) = node { own_params.push(ty::GenericParamDef { index: next_index(), name: Symbol::intern("<const_ty>"), diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 072bb727901..40204961e9c 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -1,7 +1,7 @@ use crate::bounds::Bounds; use crate::collect::ItemCtxt; use crate::constrained_generic_params as cgp; -use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter}; +use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter, RegionInferReason}; use hir::{HirId, Node}; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; @@ -117,7 +117,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen let mut is_trait = None; let mut is_default_impl_trait = None; - // FIXME: Should ItemCtxt take a LocalDefId? let icx = ItemCtxt::new(tcx, def_id); const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty(); @@ -197,7 +196,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen .type_of(param.def_id.to_def_id()) .no_bound_vars() .expect("const parameters cannot be generic"); - let ct = icx.lowerer().lower_const_param(param.hir_id, ct_ty); + let ct = icx.lowerer().lower_const_param(param.hir_id); predicates .insert((ty::ClauseKind::ConstArgHasType(ct, ct_ty).upcast(tcx), param.span)); } @@ -244,12 +243,15 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } hir::WherePredicate::RegionPredicate(region_pred) => { - let r1 = icx.lowerer().lower_lifetime(region_pred.lifetime, None); + let r1 = icx + .lowerer() + .lower_lifetime(region_pred.lifetime, RegionInferReason::RegionPredicate); predicates.extend(region_pred.bounds.iter().map(|bound| { let (r2, span) = match bound { - hir::GenericBound::Outlives(lt) => { - (icx.lowerer().lower_lifetime(lt, None), lt.ident.span) - } + hir::GenericBound::Outlives(lt) => ( + icx.lowerer().lower_lifetime(lt, RegionInferReason::RegionPredicate), + lt.ident.span, + ), bound => { span_bug!( bound.span(), 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 c1850f78f2f..abc3bb838db 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -603,7 +603,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { match item.kind { - hir::ForeignItemKind::Fn(_, _, generics) => { + hir::ForeignItemKind::Fn(_, _, generics, _) => { self.visit_early_late(item.hir_id(), generics, |this| { intravisit::walk_foreign_item(this, item); }) diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index c677fa92261..2684467a438 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -464,7 +464,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ let args = ty::GenericArgs::identity_for_item(tcx, def_id); Ty::new_fn_def(tcx, def_id.to_def_id(), args) } - ForeignItemKind::Static(t, _) => icx.lower_ty(t), + ForeignItemKind::Static(t, _, _) => icx.lower_ty(t), ForeignItemKind::Type => Ty::new_foreign(tcx, def_id.to_def_id()), }, @@ -485,7 +485,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ } Node::AnonConst(_) => anon_const_type_of(tcx, def_id), - Node::Expr(&Expr { kind: ExprKind::ConstBlock(..), .. }) => { + + Node::ConstBlock(_) => { let args = ty::GenericArgs::identity_for_item(tcx, def_id.to_def_id()); args.as_inline_const().ty() } @@ -502,7 +503,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ bug!("unexpected sort of node in type_of(): {:?}", x); } }; - if let Err(e) = icx.check_tainted_by_errors() { + if let Err(e) = icx.check_tainted_by_errors() + && !output.references_error() + { ty::EarlyBinder::bind(Ty::new_error(tcx, e)) } else { ty::EarlyBinder::bind(output) 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 b6a1799c03f..7f6f57907c2 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -18,6 +18,8 @@ use crate::bounds::Bounds; use crate::errors; use crate::hir_ty_lowering::{HirTyLowerer, OnlySelfBounds, PredicateFilter}; +use super::RegionInferReason; + impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Add a `Sized` bound to the `bounds` if appropriate. /// @@ -166,7 +168,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); } hir::GenericBound::Outlives(lifetime) => { - let region = self.lower_lifetime(lifetime, None); + let region = self.lower_lifetime(lifetime, RegionInferReason::OutlivesBound); bounds.push_region_bound( self.tcx(), ty::Binder::bind_with_vars( @@ -366,11 +368,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }, ) }); - let ty = tcx - .type_of(param.def_id) - .no_bound_vars() - .expect("ct params cannot have early bound vars"); - ty::Const::new_error(tcx, guar, ty).into() + ty::Const::new_error(tcx, guar).into() } }; num_bound_vars += 1; 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 821c5653040..3a9ef244fd3 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -15,7 +15,6 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_infer::traits::FulfillmentError; use rustc_middle::bug; use rustc_middle::query::Key; use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _}; @@ -28,6 +27,7 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::BytePos; use rustc_span::{Span, Symbol, DUMMY_SP}; +use rustc_trait_selection::traits::FulfillmentError; use rustc_trait_selection::traits::{ object_safety_violations_for_assoc_item, TraitAliasExpansionInfo, }; @@ -702,7 +702,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub(crate) fn complain_about_missing_assoc_tys( &self, associated_types: FxIndexMap<Span, FxIndexSet<DefId>>, - potential_assoc_types: Vec<Span>, + potential_assoc_types: Vec<usize>, trait_bounds: &[hir::PolyTraitRef<'_>], ) { if associated_types.values().all(|v| v.is_empty()) { 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 d641e33b299..26cabb69d25 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -214,10 +214,11 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( if let Some(¶m) = params.peek() { if param.index == 0 { if let GenericParamDefKind::Type { .. } = param.kind { + assert_eq!(&args[..], &[]); args.push( self_ty .map(|ty| ty.into()) - .unwrap_or_else(|| ctx.inferred_kind(None, param, true)), + .unwrap_or_else(|| ctx.inferred_kind(&args, param, true)), ); params.next(); } @@ -267,7 +268,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( // Since this is a const impl, we need to insert a host arg at the end of // `PartialEq`'s generics, but this errors since `Rhs` isn't specified. // To work around this, we infer all arguments until we reach the host param. - args.push(ctx.inferred_kind(Some(&args), param, infer_args)); + args.push(ctx.inferred_kind(&args, param, infer_args)); params.next(); } (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _) @@ -281,7 +282,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( GenericParamDefKind::Const { .. }, _, ) => { - args.push(ctx.provided_kind(param, arg)); + args.push(ctx.provided_kind(&args, param, arg)); args_iter.next(); params.next(); } @@ -292,7 +293,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( ) => { // We expected a lifetime argument, but got a type or const // argument. That means we're inferring the lifetimes. - args.push(ctx.inferred_kind(None, param, infer_args)); + args.push(ctx.inferred_kind(&args, param, infer_args)); force_infer_lt = Some((arg, param)); params.next(); } @@ -388,7 +389,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( (None, Some(¶m)) => { // If there are fewer arguments than parameters, it means // we're inferring the remaining arguments. - args.push(ctx.inferred_kind(Some(&args), param, infer_args)); + args.push(ctx.inferred_kind(&args, param, infer_args)); params.next(); } @@ -474,16 +475,9 @@ pub(crate) fn check_generic_arg_count( return Ok(()); } - if provided_args > max_expected_args { - invalid_args.extend( - gen_args.args[max_expected_args..provided_args].iter().map(|arg| arg.span()), - ); - }; + invalid_args.extend(min_expected_args..provided_args); let gen_args_info = if provided_args > min_expected_args { - invalid_args.extend( - gen_args.args[min_expected_args..provided_args].iter().map(|arg| arg.span()), - ); let num_redundant_args = provided_args - min_expected_args; GenericArgsInfo::ExcessLifetimes { num_redundant_args } } else { @@ -538,11 +532,7 @@ pub(crate) fn check_generic_arg_count( let num_default_params = expected_max - expected_min; let gen_args_info = if provided > expected_max { - invalid_args.extend( - gen_args.args[args_offset + expected_max..args_offset + provided] - .iter() - .map(|arg| arg.span()), - ); + invalid_args.extend((expected_max..provided).map(|i| i + args_offset)); let num_redundant_args = provided - expected_max; // Provide extra note if synthetic arguments like `impl Trait` are specified. @@ -610,7 +600,7 @@ pub(crate) fn check_generic_arg_count( explicit_late_bound, correct: lifetimes_correct .and(args_correct) - .map_err(|reported| GenericArgCountMismatch { reported: Some(reported), invalid_args }), + .map_err(|reported| GenericArgCountMismatch { reported, invalid_args }), } } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index b4305f6efb9..240a749de96 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -182,7 +182,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // For recursive traits, don't downgrade the error. (#119652) is_downgradable = false; } - tcx.check_is_object_safe(id) + tcx.is_object_safe(id) } _ => false, }) 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 54b7f7f36ed..7ec64f1feda 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -20,7 +20,6 @@ mod lint; mod object_safety; use crate::bounds::Bounds; -use crate::collect::HirPlaceholderCollector; use crate::errors::{AmbiguousLifetimeBound, WildPatTy}; use crate::hir_ty_lowering::errors::{prohibit_assoc_item_constraint, GenericsArgsErrExtend}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; @@ -34,7 +33,6 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit::{walk_generics, Visitor as _}; use rustc_hir::{GenericArg, GenericArgs, HirId}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; @@ -82,6 +80,20 @@ pub enum PredicateFilter { SelfAndAssociatedTypeBounds, } +#[derive(Debug)] +pub enum RegionInferReason<'a> { + /// Lifetime on a trait object behind a reference. + /// This allows inferring information from the reference. + BorrowedObjectLifetimeDefault, + /// A trait object's lifetime. + ObjectLifetimeDefault, + /// Generic lifetime parameter + Param(&'a ty::GenericParamDef), + RegionPredicate, + Reference, + OutlivesBound, +} + /// A context which can lower type-system entities from the [HIR][hir] to /// the [`rustc_middle::ty`] representation. /// @@ -89,26 +101,17 @@ pub enum PredicateFilter { pub trait HirTyLowerer<'tcx> { fn tcx(&self) -> TyCtxt<'tcx>; - /// Returns the [`DefId`] of the overarching item whose constituents get lowered. - fn item_def_id(&self) -> DefId; - - /// Returns `true` if the current context allows the use of inference variables. - fn allow_infer(&self) -> bool; + /// Returns the [`LocalDefId`] of the overarching item whose constituents get lowered. + fn item_def_id(&self) -> LocalDefId; /// Returns the region to use when a lifetime is omitted (and not elided). - fn re_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) - -> Option<ty::Region<'tcx>>; + fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx>; /// Returns the type to use when a type is omitted. fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx>; /// Returns the const to use when a const is omitted. - fn ct_infer( - &self, - ty: Ty<'tcx>, - param: Option<&ty::GenericParamDef>, - span: Span, - ) -> Const<'tcx>; + fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx>; /// Probe bounds in scope where the bounded type coincides with the given type parameter. /// @@ -151,6 +154,14 @@ pub trait HirTyLowerer<'tcx> { poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Ty<'tcx>; + fn lower_fn_sig( + &self, + decl: &hir::FnDecl<'tcx>, + generics: Option<&hir::Generics<'_>>, + hir_id: HirId, + hir_ty: Option<&hir::Ty<'_>>, + ) -> (Vec<Ty<'tcx>>, Ty<'tcx>); + /// Returns `AdtDef` if `ty` is an ADT. /// /// Note that `ty` might be a alias type that needs normalization. @@ -215,12 +226,11 @@ pub(crate) enum GenericArgPosition { /// A marker denoting that the generic arguments that were /// provided did not match the respective generic parameters. -#[derive(Clone, Default, Debug)] +#[derive(Clone, Debug)] pub struct GenericArgCountMismatch { - /// Indicates whether a fatal error was reported (`Some`), or just a lint (`None`). - pub reported: Option<ErrorGuaranteed>, - /// A list of spans of arguments provided that were not valid. - pub invalid_args: Vec<Span>, + pub reported: ErrorGuaranteed, + /// A list of indices of arguments provided that were not valid. + pub invalid_args: Vec<usize>, } /// Decorates the result of a generic argument count mismatch @@ -240,13 +250,14 @@ pub trait GenericArgsLowerer<'a, 'tcx> { fn provided_kind( &mut self, + preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx>; fn inferred_kind( &mut self, - args: Option<&[ty::GenericArg<'tcx>]>, + preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, infer_args: bool, ) -> ty::GenericArg<'tcx>; @@ -258,7 +269,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub fn lower_lifetime( &self, lifetime: &hir::Lifetime, - def: Option<&ty::GenericParamDef>, + reason: RegionInferReason<'_>, ) -> ty::Region<'tcx> { let tcx = self.tcx(); let lifetime_name = |def_id| tcx.hir().name(tcx.local_def_id_to_hir_id(def_id)); @@ -292,21 +303,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(rbv::ResolvedArg::Error(guar)) => ty::Region::new_error(tcx, guar), - None => { - self.re_infer(def, lifetime.ident.span).unwrap_or_else(|| { - debug!(?lifetime, "unelided lifetime in signature"); - - // This indicates an illegal lifetime - // elision. `resolve_lifetime` should have - // reported an error in this case -- but if - // not, let's error out. - ty::Region::new_error_with_message( - tcx, - lifetime.ident.span, - "unelided lifetime in signature", - ) - }) - } + None => self.re_infer(lifetime.ident.span, reason), } } @@ -404,10 +401,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty.is_some(), ); - if let Err(err) = &arg_count.correct - && let Some(reported) = err.reported - { - self.set_tainted_by_errors(reported); + if let Err(err) = &arg_count.correct { + self.set_tainted_by_errors(err.reported); } // Skip processing if type has no generic parameters. @@ -423,8 +418,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { def_id: DefId, generic_args: &'a GenericArgs<'tcx>, span: Span, - inferred_params: Vec<Span>, infer_args: bool, + incorrect_args: &'a Result<(), GenericArgCountMismatch>, } impl<'a, 'tcx> GenericArgsLowerer<'a, 'tcx> for GenericArgsCtxt<'a, 'tcx> { @@ -439,12 +434,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn provided_kind( &mut self, + _preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { let tcx = self.lowerer.tcx(); - let mut handle_ty_args = |has_default, ty: &hir::Ty<'tcx>| { + if let Err(incorrect) = self.incorrect_args { + if incorrect.invalid_args.contains(&(param.index as usize)) { + return param.to_error(tcx); + } + } + + let handle_ty_args = |has_default, ty: &hir::Ty<'tcx>| { if has_default { tcx.check_optional_stability( param.def_id, @@ -461,17 +463,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }, ); } - if let (hir::TyKind::Infer, false) = (&ty.kind, self.lowerer.allow_infer()) { - self.inferred_params.push(ty.span); - Ty::new_misc_error(tcx).into() - } else { - self.lowerer.lower_ty(ty).into() - } + self.lowerer.lower_ty(ty).into() }; match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - self.lowerer.lower_lifetime(lt, Some(param)).into() + self.lowerer.lower_lifetime(lt, RegionInferReason::Param(param)).into() } (&GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { handle_ty_args(has_default, ty) @@ -485,17 +482,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Const::from_anon_const(tcx, did).into() } (&GenericParamDefKind::Const { .. }, hir::GenericArg::Infer(inf)) => { - let ty = tcx - .at(self.span) - .type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"); - if self.lowerer.allow_infer() { - self.lowerer.ct_infer(ty, Some(param), inf.span).into() - } else { - self.inferred_params.push(inf.span); - ty::Const::new_misc_error(tcx, ty).into() - } + self.lowerer.ct_infer(Some(param), inf.span).into() } (kind, arg) => span_bug!( self.span, @@ -506,38 +493,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn inferred_kind( &mut self, - args: Option<&[ty::GenericArg<'tcx>]>, + preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, infer_args: bool, ) -> ty::GenericArg<'tcx> { let tcx = self.lowerer.tcx(); + + if let Err(incorrect) = self.incorrect_args { + if incorrect.invalid_args.contains(&(param.index as usize)) { + return param.to_error(tcx); + } + } match param.kind { - GenericParamDefKind::Lifetime => self - .lowerer - .re_infer(Some(param), self.span) - .unwrap_or_else(|| { - debug!(?param, "unelided lifetime in signature"); - - // This indicates an illegal lifetime in a non-assoc-trait position - ty::Region::new_error_with_message( - tcx, - self.span, - "unelided lifetime in signature", - ) - }) - .into(), + GenericParamDefKind::Lifetime => { + self.lowerer.re_infer(self.span, RegionInferReason::Param(param)).into() + } GenericParamDefKind::Type { has_default, .. } => { if !infer_args && has_default { // No type parameter provided, but a default exists. - let args = args.unwrap(); - if args.iter().any(|arg| match arg.unpack() { - GenericArgKind::Type(ty) => ty.references_error(), - _ => false, - }) { + if let Some(prev) = + preceding_args.iter().find_map(|arg| match arg.unpack() { + GenericArgKind::Type(ty) => ty.error_reported().err(), + _ => None, + }) + { // Avoid ICE #86756 when type error recovery goes awry. - return Ty::new_misc_error(tcx).into(); + return Ty::new_error(tcx, prev).into(); } - tcx.at(self.span).type_of(param.def_id).instantiate(tcx, args).into() + tcx.at(self.span) + .type_of(param.def_id) + .instantiate(tcx, preceding_args) + .into() } else if infer_args { self.lowerer.ty_infer(Some(param), self.span).into() } else { @@ -552,46 +538,45 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .no_bound_vars() .expect("const parameter types cannot be generic"); if let Err(guar) = ty.error_reported() { - return ty::Const::new_error(tcx, guar, ty).into(); + return ty::Const::new_error(tcx, guar).into(); } // FIXME(effects) see if we should special case effect params here if !infer_args && has_default { tcx.const_param_default(param.def_id) - .instantiate(tcx, args.unwrap()) + .instantiate(tcx, preceding_args) .into() } else { if infer_args { - self.lowerer.ct_infer(ty, Some(param), self.span).into() + self.lowerer.ct_infer(Some(param), self.span).into() } else { // We've already errored above about the mismatch. - ty::Const::new_misc_error(tcx, ty).into() + ty::Const::new_misc_error(tcx).into() } } } } } } - - let mut args_ctx = GenericArgsCtxt { - lowerer: self, - def_id, - span, - generic_args: segment.args(), - inferred_params: vec![], - infer_args: segment.infer_args, - }; if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness && generics.has_self && !tcx.has_attr(def_id, sym::const_trait) { - let e = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { + let reported = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { span, modifier: constness.as_str(), }); - self.set_tainted_by_errors(e); - arg_count.correct = - Err(GenericArgCountMismatch { reported: Some(e), invalid_args: vec![] }); + self.set_tainted_by_errors(reported); + arg_count.correct = Err(GenericArgCountMismatch { reported, invalid_args: vec![] }); } + + let mut args_ctx = GenericArgsCtxt { + lowerer: self, + def_id, + span, + generic_args: segment.args(), + infer_args: segment.infer_args, + incorrect_args: &arg_count.correct, + }; let args = lower_generic_args( tcx, def_id, @@ -1298,7 +1283,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .copied() .filter(|&(impl_, _)| { infcx.probe(|_| { - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); let self_ty = ocx.normalize(&ObligationCause::dummy(), param_env, self_ty); let impl_args = infcx.fresh_args_for_item(span, impl_); @@ -1477,16 +1462,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let def_id = self.item_def_id(); debug!(item_def_id = ?def_id); - let parent_def_id = def_id - .as_local() - .map(|def_id| tcx.local_def_id_to_hir_id(def_id)) - .map(|hir_id| tcx.hir().get_parent_item(hir_id).to_def_id()); + // FIXME: document why/how this is different from `tcx.local_parent(def_id)` + let parent_def_id = + tcx.hir().get_parent_item(tcx.local_def_id_to_hir_id(def_id)).to_def_id(); debug!(?parent_def_id); // If the trait in segment is the same as the trait defining the item, // use the `<Self as ..>` syntax in the error. - let is_part_of_self_trait_constraints = def_id == trait_def_id; - let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id); + let is_part_of_self_trait_constraints = def_id.to_def_id() == trait_def_id; + let is_part_of_fn_in_self_trait = parent_def_id == trait_def_id; let type_names = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait { vec!["Self".to_string()] @@ -1914,7 +1898,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// Early-bound const parameters get lowered to [`ty::ConstKind::Param`] /// and late-bound ones to [`ty::ConstKind::Bound`]. - pub(crate) fn lower_const_param(&self, hir_id: HirId, param_ty: Ty<'tcx>) -> Const<'tcx> { + pub(crate) fn lower_const_param(&self, hir_id: HirId) -> Const<'tcx> { let tcx = self.tcx(); match tcx.named_bound_var(hir_id) { Some(rbv::ResolvedArg::EarlyBound(def_id)) => { @@ -1924,12 +1908,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; let name = tcx.item_name(def_id); - ty::Const::new_param(tcx, ty::ParamConst::new(index, name), param_ty) + ty::Const::new_param(tcx, ty::ParamConst::new(index, name)) } Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { - ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index), param_ty) + ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index)) } - Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar, param_ty), + Some(rbv::ResolvedArg::Error(guar)) => ty::Const::new_error(tcx, guar), arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", hir_id), } } @@ -1967,7 +1951,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } let sig_generics = self.tcx().generics_of(sig_id); - let parent = self.tcx().parent(self.item_def_id()); + let parent = self.tcx().local_parent(self.item_def_id()); let parent_generics = self.tcx().generics_of(parent); let parent_is_trait = (self.tcx().def_kind(parent) == DefKind::Trait) as usize; @@ -2006,7 +1990,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let sig = self.tcx().fn_sig(sig_id); let sig_generics = self.tcx().generics_of(sig_id); - let parent = self.tcx().parent(self.item_def_id()); + let parent = self.tcx().local_parent(self.item_def_id()); let parent_def_kind = self.tcx().def_kind(parent); let sig = if let DefKind::Impl { .. } = parent_def_kind @@ -2054,7 +2038,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::TyKind::Slice(ty) => Ty::new_slice(tcx, self.lower_ty(ty)), hir::TyKind::Ptr(mt) => Ty::new_ptr(tcx, self.lower_ty(mt.ty), mt.mutbl), hir::TyKind::Ref(region, mt) => { - let r = self.lower_lifetime(region, None); + let r = self.lower_lifetime(region, RegionInferReason::Reference); debug!(?r); let t = self.lower_ty_common(mt.ty, true, false); Ty::new_ref(tcx, r, t, mt.mutbl) @@ -2145,7 +2129,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } hir::TyKind::Array(ty, length) => { let length = match length { - hir::ArrayLen::Infer(inf) => self.ct_infer(tcx.types.usize, None, inf.span), + hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span), hir::ArrayLen::Body(constant) => { ty::Const::from_anon_const(tcx, constant.def_id) } @@ -2176,17 +2160,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } _ => (expr, None), }; - let c = match &expr.kind { + let (c, c_ty) = match &expr.kind { hir::ExprKind::Lit(lit) => { let lit_input = LitToConstInput { lit: &lit.node, ty, neg: neg.is_some() }; - match tcx.lit_to_const(lit_input) { + let ct = match tcx.lit_to_const(lit_input) { Ok(c) => c, Err(LitToConstError::Reported(err)) => { - ty::Const::new_error(tcx, err, ty) + ty::Const::new_error(tcx, err) } Err(LitToConstError::TypeError) => todo!(), - } + }; + (ct, ty) } hir::ExprKind::Path(hir::QPath::Resolved( @@ -2204,19 +2189,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .type_of(def_id) .no_bound_vars() .expect("const parameter types cannot be generic"); - self.lower_const_param(expr.hir_id, ty) + let ct = self.lower_const_param(expr.hir_id); + (ct, ty) } _ => { let err = tcx .dcx() .emit_err(crate::errors::NonConstRange { span: expr.span }); - ty::Const::new_error(tcx, err, ty) + (ty::Const::new_error(tcx, err), Ty::new_error(tcx, err)) } }; - self.record_ty(expr.hir_id, c.ty(), expr.span); + self.record_ty(expr.hir_id, c_ty, expr.span); if let Some((id, span)) = neg { - self.record_ty(id, c.ty(), span); + self.record_ty(id, c_ty, span); } c }; @@ -2283,7 +2269,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &lifetimes[i] ) }; - self.lower_lifetime(lifetime, None).into() + self.lower_lifetime(lifetime, RegionInferReason::Param(¶m)).into() } else { tcx.mk_param_from_def(param) } @@ -2322,92 +2308,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let bound_vars = tcx.late_bound_vars(hir_id); debug!(?bound_vars); - // We proactively collect all the inferred type params to emit a single error per fn def. - let mut visitor = HirPlaceholderCollector::default(); - let mut infer_replacements = vec![]; - - if let Some(generics) = generics { - walk_generics(&mut visitor, generics); - } - - let input_tys: Vec<_> = decl - .inputs - .iter() - .enumerate() - .map(|(i, a)| { - if let hir::TyKind::Infer = a.kind - && !self.allow_infer() - { - if let Some(suggested_ty) = - self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, Some(i)) - { - infer_replacements.push((a.span, suggested_ty.to_string())); - return Ty::new_error_with_message( - self.tcx(), - a.span, - suggested_ty.to_string(), - ); - } - } - - // Only visit the type looking for `_` if we didn't fix the type above - visitor.visit_ty(a); - self.lower_arg_ty(a, None) - }) - .collect(); - - let output_ty = match decl.output { - hir::FnRetTy::Return(output) => { - if let hir::TyKind::Infer = output.kind - && !self.allow_infer() - && let Some(suggested_ty) = - self.suggest_trait_fn_ty_for_impl_fn_infer(hir_id, None) - { - infer_replacements.push((output.span, suggested_ty.to_string())); - Ty::new_error_with_message(self.tcx(), output.span, suggested_ty.to_string()) - } else { - visitor.visit_ty(output); - self.lower_ty(output) - } - } - hir::FnRetTy::DefaultReturn(..) => tcx.types.unit, - }; + let (input_tys, output_ty) = self.lower_fn_sig(decl, generics, hir_id, hir_ty); debug!(?output_ty); let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi); let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars); - if !self.allow_infer() && !(visitor.0.is_empty() && infer_replacements.is_empty()) { - // We always collect the spans for placeholder types when evaluating `fn`s, but we - // only want to emit an error complaining about them if infer types (`_`) are not - // allowed. `allow_infer` gates this behavior. We check for the presence of - // `ident_span` to not emit an error twice when we have `fn foo(_: fn() -> _)`. - - let mut diag = crate::collect::placeholder_type_error_diag( - tcx, - generics, - visitor.0, - infer_replacements.iter().map(|(s, _)| *s).collect(), - true, - hir_ty, - "function", - ); - - if !infer_replacements.is_empty() { - diag.multipart_suggestion( - format!( - "try replacing `_` with the type{} in the corresponding trait method signature", - rustc_errors::pluralize!(infer_replacements.len()), - ), - infer_replacements, - Applicability::MachineApplicable, - ); - } - - self.set_tainted_by_errors(diag.emit()); - } - // Find any late-bound regions declared in return type that do // not appear in the arguments. These are not well-formed. // @@ -2437,7 +2344,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// corresponding function in the trait that the impl implements, if it exists. /// If arg_idx is Some, then it corresponds to an input type index, otherwise it /// corresponds to the return type. - fn suggest_trait_fn_ty_for_impl_fn_infer( + pub(super) fn suggest_trait_fn_ty_for_impl_fn_infer( &self, fn_hir_id: HirId, arg_idx: Option<usize>, 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 4f7a39d0250..34924f09d09 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 @@ -1,5 +1,7 @@ use crate::bounds::Bounds; -use crate::hir_ty_lowering::{GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds}; +use crate::hir_ty_lowering::{ + GenericArgCountMismatch, GenericArgCountResult, OnlySelfBounds, RegionInferReason, +}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::{codes::*, struct_span_code_err}; use rustc_hir as hir; @@ -141,9 +143,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // `trait_object_dummy_self`, so check for that. let references_self = match pred.skip_binder().term.unpack() { ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()), - ty::TermKind::Const(c) => { - c.ty().walk().any(|arg| arg == dummy_self.into()) - } + // FIXME(associated_const_equality): We should walk the const instead of not doing anything + ty::TermKind::Const(_) => false, }; // If the projection output contains `Self`, force the user to @@ -321,30 +322,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Use explicitly-specified region bound. let region_bound = if !lifetime.is_elided() { - self.lower_lifetime(lifetime, None) + self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault) } else { self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { if tcx.named_bound_var(lifetime.hir_id).is_some() { - self.lower_lifetime(lifetime, None) + self.lower_lifetime(lifetime, RegionInferReason::ObjectLifetimeDefault) } else { - self.re_infer(None, span).unwrap_or_else(|| { - let err = struct_span_code_err!( - tcx.dcx(), - span, - E0228, - "the lifetime bound for this object type cannot be deduced \ - from context; please supply an explicit bound" - ); - let e = if borrowed { - // We will have already emitted an error E0106 complaining about a - // missing named lifetime in `&dyn Trait`, so we elide this one. - err.delay_as_bug() + self.re_infer( + span, + if borrowed { + RegionInferReason::ObjectLifetimeDefault } else { - err.emit() - }; - self.set_tainted_by_errors(e); - ty::Region::new_error(tcx, e) - }) + RegionInferReason::BorrowedObjectLifetimeDefault + }, + ) } }) }; diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 10101aa046e..13993a1992b 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -67,7 +67,7 @@ fn diagnostic_hir_wf_check<'tcx>( impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { let infcx = self.tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let tcx_ty = self.icx.lower_ty(ty); // This visitor can walk into binders, resulting in the `tcx_ty` to @@ -158,7 +158,7 @@ fn diagnostic_hir_wf_check<'tcx>( }, hir::Node::Field(field) => vec![field.ty], hir::Node::ForeignItem(ForeignItem { - kind: ForeignItemKind::Static(ty, _), .. + kind: ForeignItemKind::Static(ty, _, _), .. }) => vec![*ty], hir::Node::GenericParam(hir::GenericParam { kind: hir::GenericParamKind::Type { default: Some(ty), .. }, diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 002be61196a..5cc1ec71757 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -86,6 +86,8 @@ fn enforce_impl_params_are_constrained( let impl_predicates = tcx.predicates_of(impl_def_id); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).map(ty::EarlyBinder::instantiate_identity); + impl_trait_ref.error_reported()?; + let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref); cgp::identify_constrained_generic_params( tcx, 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 6967cb4d9d0..f3ce3ab6655 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 @@ -196,7 +196,7 @@ fn get_impl_args( impl2_node: Node, ) -> Result<(GenericArgsRef<'_>, GenericArgsRef<'_>), ErrorGuaranteed> { let infcx = &tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); let param_env = tcx.param_env(impl1_def_id); let impl1_span = tcx.def_span(impl1_def_id); let assumed_wf_types = ocx.assumed_wf_types_and_report_errors(param_env, impl1_def_id)?; diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 65b02a2ec56..8fe81851f93 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -190,6 +190,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) { } }); + // Freeze definitions as we don't add new ones at this point. This improves performance by + // allowing lock-free access to them. + tcx.untracked().definitions.freeze(); + // FIXME: Remove this when we implement creating `DefId`s // for anon constants during their parents' typeck. // Typeck all body owners in parallel will produce queries @@ -201,10 +205,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) { } }); - // Freeze definitions as we don't add new ones at this point. This improves performance by - // allowing lock-free access to them. - tcx.untracked().definitions.freeze(); - tcx.ensure().check_unused_traits(()); } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index a8e0b3fc079..6f2febd86b0 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -84,6 +84,7 @@ impl<'a> State<'a> { Node::ImplItem(a) => self.print_impl_item(a), Node::Variant(a) => self.print_variant(a), Node::AnonConst(a) => self.print_anon_const(a), + Node::ConstBlock(a) => self.print_inline_const(a), Node::Expr(a) => self.print_expr(a), Node::ExprField(a) => self.print_expr_field(a), Node::Stmt(a) => self.print_stmt(a), @@ -345,12 +346,12 @@ impl<'a> State<'a> { self.maybe_print_comment(item.span.lo()); self.print_outer_attributes(self.attrs(item.hir_id())); match item.kind { - hir::ForeignItemKind::Fn(decl, arg_names, generics) => { + hir::ForeignItemKind::Fn(decl, arg_names, generics, safety) => { self.head(""); self.print_fn( decl, hir::FnHeader { - safety: hir::Safety::Safe, + safety, constness: hir::Constness::NotConst, abi: Abi::Rust, asyncness: hir::IsAsync::NotAsync, @@ -364,7 +365,8 @@ impl<'a> State<'a> { self.word(";"); self.end() // end the outer fn box } - hir::ForeignItemKind::Static(t, m) => { + hir::ForeignItemKind::Static(t, m, safety) => { + self.print_safety(safety); self.head("static"); if m.is_mut() { self.word_space("mut"); @@ -1048,10 +1050,10 @@ impl<'a> State<'a> { self.end() } - fn print_inline_const(&mut self, constant: &hir::Expr<'_>) { + fn print_inline_const(&mut self, constant: &hir::ConstBlock) { self.ibox(INDENT_UNIT); self.word_space("const"); - self.print_expr(constant); + self.ann.nested(self, Nested::Body(constant.body)); self.end() } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 14a6177141c..ac7ed3e26f9 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -485,7 +485,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Since this is a return parameter type it is safe to unwrap. - let ret_param_ty = projection.skip_binder().term.ty().unwrap(); + let ret_param_ty = projection.skip_binder().term.expect_type(); let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty); debug!(?ret_param_ty); @@ -956,7 +956,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let output_ty = self.resolve_vars_if_possible(predicate.term); debug!("deduce_future_output_from_projection: output_ty={:?}", output_ty); // This is a projection on a Fn trait so will always be a type. - Some(output_ty.ty().unwrap()) + Some(output_ty.expect_type()) } /// Converts the types that the user supplied, in case that doing diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 93726ce2b3e..dbaa6e398c8 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -41,6 +41,7 @@ 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::relate::RelateResult; use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; use rustc_infer::traits::{IfExpressionCause, MatchExpressionArmCause}; use rustc_infer::traits::{Obligation, PredicateObligation}; @@ -51,7 +52,6 @@ use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion, }; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt}; use rustc_session::parse::feature_err; diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index fa147f9bfcf..d2a5924c8bb 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -350,7 +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(), DUMMY_SP) + self.next_const_var(DUMMY_SP) } else { ct } @@ -827,7 +827,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) else { return; }; - let in_scope_methods = self.probe_for_name_many( + + let Ok(in_scope_methods) = self.probe_for_name_many( probe::Mode::MethodCall, path.ident, Some(expected), @@ -835,11 +836,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty, deref.hir_id, probe::ProbeScope::TraitsInScope, - ); + ) else { + return; + }; + let other_methods_in_scope: Vec<_> = in_scope_methods.iter().filter(|c| c.item.def_id != pick.item.def_id).collect(); - let all_methods = self.probe_for_name_many( + let Ok(all_methods) = self.probe_for_name_many( probe::Mode::MethodCall, path.ident, Some(expected), @@ -847,7 +851,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty, deref.hir_id, probe::ProbeScope::AllTraits, - ); + ) else { + return; + }; + let suggestions: Vec<_> = all_methods .into_iter() .filter(|c| c.item.def_id != pick.item.def_id) diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 2f92a304bf0..5b27ebe3416 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -13,7 +13,6 @@ use crate::errors::{ YieldExprOutsideOfCoroutine, }; use crate::fatally_break_rust; -use crate::method::SelfSource; use crate::type_error_struct; use crate::CoroutineTypes; use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation}; @@ -32,6 +31,7 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, HirId, QPath}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _; @@ -41,7 +41,7 @@ use rustc_infer::infer::InferOk; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase}; -use rustc_middle::ty::error::{ExpectedFound, TypeError::Sorts}; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; @@ -223,7 +223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = ensure_sufficient_stack(|| match &expr.kind { hir::ExprKind::Path( qpath @ (hir::QPath::Resolved(..) | hir::QPath::TypeRelative(..)), - ) => self.check_expr_path(qpath, expr, args, call), + ) => self.check_expr_path(qpath, expr, Some(args), call), _ => self.check_expr_kind(expr, expected), }); let ty = self.resolve_vars_if_possible(ty); @@ -290,7 +290,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Path(QPath::LangItem(lang_item, _)) => { self.check_lang_item_path(lang_item, expr) } - ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[], None), + ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, None, None), ExprKind::InlineAsm(asm) => { // We defer some asm checks as we may not have resolved the input and output types yet (they may still be infer vars). self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id)); @@ -335,7 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected), ExprKind::Array(args) => self.check_expr_array(args, expected, expr), - ExprKind::ConstBlock(ref block) => self.check_expr_with_expectation(block, expected), + ExprKind::ConstBlock(ref block) => self.check_expr_const_block(block, expected), ExprKind::Repeat(element, ref count) => { self.check_expr_repeat(element, count, expected, expr) } @@ -502,12 +502,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, qpath: &'tcx hir::QPath<'tcx>, expr: &'tcx hir::Expr<'tcx>, - args: &'tcx [hir::Expr<'tcx>], + args: Option<&'tcx [hir::Expr<'tcx>]>, call: Option<&'tcx hir::Expr<'tcx>>, ) -> Ty<'tcx> { let tcx = self.tcx; let (res, opt_ty, segs) = - self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span, Some(args)); + self.resolve_ty_and_res_fully_qualified_call(qpath, expr.hir_id, expr.span); let ty = match res { Res::Err => { self.suggest_assoc_method_call(segs); @@ -564,7 +564,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We just want to check sizedness, so instead of introducing // placeholder lifetimes with probing, we just replace higher lifetimes // with fresh vars. - let span = args.get(i).map(|a| a.span).unwrap_or(expr.span); + let span = args.and_then(|args| args.get(i)).map_or(expr.span, |arg| arg.span); let input = self.instantiate_binder_with_fresh_vars( span, infer::BoundRegionConversionTime::FnCall, @@ -683,7 +683,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_mismatched_types_on_tail( &mut err, expr, ty, e_ty, target_id, ); - let error = Some(Sorts(ExpectedFound { expected: ty, found: e_ty })); + let error = + Some(TypeError::Sorts(ExpectedFound { expected: ty, found: e_ty })); self.annotate_loop_expected_due_to_inference(err, expr, error); if let Some(val) = self.err_ctxt().ty_kind_suggestion(self.param_env, ty) @@ -1331,9 +1332,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let rcvr_t = self.check_expr(rcvr); // no need to check for bot/err -- callee does that let rcvr_t = self.structurally_resolve_type(rcvr.span, rcvr_t); - let span = segment.ident.span; - let method = match self.lookup_method(rcvr_t, segment, span, expr, rcvr, args) { + let method = match self.lookup_method(rcvr_t, segment, segment.ident.span, expr, rcvr, args) + { Ok(method) => { // We could add a "consider `foo::<params>`" suggestion here, but I wasn't able to // trigger this codepath causing `structurally_resolve_type` to emit an error. @@ -1342,18 +1343,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Err(error) => { if segment.ident.name != kw::Empty { - if let Some(err) = self.report_method_error( - span, - Some(rcvr), - rcvr_t, - segment.ident, - expr.hir_id, - SelfSource::MethodCall(rcvr), - error, - Some(args), - expected, - false, - ) { + if let Some(err) = + self.report_method_error(expr.hir_id, rcvr_t, error, expected, false) + { err.emit(); } } @@ -1362,7 +1354,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Call the generic checker. - self.check_method_argument_types(span, expr, method, args, DontTupleArguments, expected) + self.check_method_argument_types( + segment.ident.span, + expr, + method, + args, + DontTupleArguments, + expected, + ) } fn check_expr_cast( @@ -1459,6 +1458,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + fn check_expr_const_block( + &self, + block: &'tcx hir::ConstBlock, + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { + let body = self.tcx.hir().body(block.body); + + // Create a new function context. + let def_id = block.def_id; + let fcx = FnCtxt::new(self, self.param_env, def_id); + crate::GatherLocalsVisitor::new(&fcx).visit_body(body); + + let ty = fcx.check_expr_with_expectation(body.value, expected); + fcx.require_type_is_sized(ty, body.value.span, ObligationCauseCode::ConstSized); + fcx.write_ty(block.hir_id, ty); + ty + } + fn check_expr_repeat( &self, element: &'tcx hir::Expr<'tcx>, @@ -1674,6 +1691,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut error_happened = false; + if variant.fields.len() != remaining_fields.len() { + // Some field is defined more than once. Make sure we don't try to + // instantiate this struct in static/const context. + let guar = + self.dcx().span_delayed_bug(expr.span, "struct fields have non-unique names"); + self.set_tainted_by_errors(guar); + error_happened = true; + } + // Type-check each field. for (idx, field) in hir_fields.iter().enumerate() { let ident = tcx.adjust_ident(field.ident, variant.def_id); @@ -3049,7 +3075,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.commit_if_ok(|snapshot| { let outer_universe = self.universe(); - let ocx = ObligationCtxt::new(self); + let ocx = ObligationCtxt::new_with_diagnostics(self); let impl_args = self.fresh_args_for_item(base_expr.span, impl_def_id); let impl_trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(self.tcx, impl_args); @@ -3337,7 +3363,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let field_ty = self.field_ty(expr.span, field, args); - // FIXME: DSTs with static alignment should be allowed + // Enums are anyway always sized. But just to safeguard against future + // language extensions, let's double-check. self.require_type_is_sized(field_ty, expr.span, ObligationCauseCode::Misc); if field.vis.is_accessible_from(sub_def_scope, self.tcx) { @@ -3365,8 +3392,19 @@ 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, ObligationCauseCode::Misc); + if self.tcx.features().offset_of_slice { + self.require_type_has_static_alignment( + field_ty, + expr.span, + ObligationCauseCode::Misc, + ); + } else { + 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); @@ -3386,10 +3424,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Ok(index) = field.as_str().parse::<usize>() && field.name == sym::integer(index) { - for ty in tys.iter().take(index + 1) { - self.require_type_is_sized(ty, expr.span, ObligationCauseCode::Misc); - } if let Some(&field_ty) = tys.get(index) { + if self.tcx.features().offset_of_slice { + self.require_type_has_static_alignment( + field_ty, + expr.span, + ObligationCauseCode::Misc, + ); + } else { + self.require_type_is_sized( + field_ty, + expr.span, + ObligationCauseCode::Misc, + ); + } + field_indices.push((FIRST_VARIANT, index.into())); current_container = field_ty; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 0c10c67db8c..e354e1ec59c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1,6 +1,6 @@ use crate::callee::{self, DeferredCallResolution}; use crate::errors::{self, CtorIsPrivate}; -use crate::method::{self, MethodCallee, SelfSource}; +use crate::method::{self, MethodCallee}; use crate::rvalue_scopes; use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy}; use rustc_data_structures::fx::FxHashSet; @@ -16,7 +16,7 @@ use rustc_hir_analysis::hir_ty_lowering::generics::{ }; use rustc_hir_analysis::hir_ty_lowering::{ ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgsLowerer, - GenericPathSegment, HirTyLowerer, IsMethodCall, + GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason, }; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; @@ -386,6 +386,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + pub fn require_type_has_static_alignment( + &self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { + if !ty.references_error() { + let tail = + self.tcx.struct_tail_with_normalize(ty, |ty| self.normalize(span, ty), || {}); + // Sized types have static alignment, and so do slices. + if tail.is_trivially_sized(self.tcx) || matches!(tail.kind(), ty::Slice(..)) { + // Nothing else is required here. + } else { + // We can't be sure, let's required full `Sized`. + let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); + self.require_type_meets(ty, span, code, lang_item); + } + } + } + pub fn register_bound( &self, ty: Ty<'tcx>, @@ -436,7 +456,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn lower_array_length(&self, length: &hir::ArrayLen<'tcx>) -> ty::Const<'tcx> { match length { - hir::ArrayLen::Infer(inf) => self.ct_infer(self.tcx.types.usize, None, inf.span), + hir::ArrayLen::Infer(inf) => self.ct_infer(None, inf.span), hir::ArrayLen::Body(anon_const) => { let span = self.tcx.def_span(anon_const.def_id); let c = ty::Const::from_anon_const(self.tcx, anon_const.def_id); @@ -735,7 +755,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { qpath: &'tcx QPath<'tcx>, hir_id: HirId, span: Span, - args: Option<&'tcx [hir::Expr<'tcx>]>, ) -> (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]) { debug!( "resolve_ty_and_res_fully_qualified_call: qpath={:?} hir_id={:?} span={:?}", @@ -828,14 +847,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if item_name.name != kw::Empty { if let Some(e) = self.report_method_error( - span, - None, - ty.normalized, - item_name, hir_id, - SelfSource::QPath(qself), + ty.normalized, error, - args, Expectation::NoExpectation, trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021 ) { @@ -1072,7 +1086,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::ImplContainer => { if segments.len() == 1 { // `<T>::assoc` will end up here, and so - // can `T::assoc`. It this came from an + // can `T::assoc`. If this came from an // inherent impl, we need to record the // `T` for posterity (see `UserSelfTy` for // details). @@ -1118,7 +1132,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // to add defaults. If the user provided *too many* types, that's // a problem. - let mut infer_args_for_err = FxHashSet::default(); + let mut infer_args_for_err = None; let mut explicit_late_bound = ExplicitLateBound::No; for &GenericPathSegment(def_id, index) in &generic_segments { @@ -1136,9 +1150,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { explicit_late_bound = ExplicitLateBound::Yes; } - if let Err(GenericArgCountMismatch { reported: Some(e), .. }) = arg_count.correct { - infer_args_for_err.insert(index); - self.set_tainted_by_errors(e); // See issue #53251. + if let Err(GenericArgCountMismatch { reported, .. }) = arg_count.correct { + infer_args_for_err + .get_or_insert_with(|| (reported, FxHashSet::default())) + .1 + .insert(index); + self.set_tainted_by_errors(reported); // See issue #53251. } } @@ -1232,15 +1249,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let def_id = res.def_id(); - let arg_count = GenericArgCountResult { - explicit_late_bound, - correct: if infer_args_for_err.is_empty() { - Ok(()) - } else { - Err(GenericArgCountMismatch::default()) - }, + let (correct, infer_args_for_err) = match infer_args_for_err { + Some((reported, args)) => { + (Err(GenericArgCountMismatch { reported, invalid_args: vec![] }), args) + } + None => (Ok(()), Default::default()), }; + let arg_count = GenericArgCountResult { explicit_late_bound, correct }; + struct CtorGenericArgsCtxt<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, span: Span, @@ -1272,13 +1289,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn provided_kind( &mut self, + _preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { match (¶m.kind, arg) { - (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - self.fcx.lowerer().lower_lifetime(lt, Some(param)).into() - } + (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => self + .fcx + .lowerer() + .lower_lifetime(lt, RegionInferReason::Param(param)) + .into(), (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { self.fcx.lower_ty(ty).raw.into() } @@ -1292,20 +1312,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &GenericParamDefKind::Const { has_default, is_host_effect }, GenericArg::Infer(inf), ) => { - let tcx = self.fcx.tcx(); - if has_default && is_host_effect { self.fcx.var_for_effect(param) } else { - self.fcx - .ct_infer( - tcx.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), - Some(param), - inf.span, - ) - .into() + self.fcx.ct_infer(Some(param), inf.span).into() } } _ => unreachable!(), @@ -1314,21 +1324,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn inferred_kind( &mut self, - args: Option<&[ty::GenericArg<'tcx>]>, + preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, infer_args: bool, ) -> ty::GenericArg<'tcx> { let tcx = self.fcx.tcx(); match param.kind { - GenericParamDefKind::Lifetime => { - self.fcx.re_infer(Some(param), self.span).unwrap().into() - } + GenericParamDefKind::Lifetime => self + .fcx + .re_infer( + self.span, + rustc_hir_analysis::hir_ty_lowering::RegionInferReason::Param(param), + ) + .into(), GenericParamDefKind::Type { has_default, .. } => { if !infer_args && has_default { // If we have a default, then it doesn't matter that we're not // inferring the type arguments: we provide the default where any // is missing. - tcx.type_of(param.def_id).instantiate(tcx, args.unwrap()).into() + tcx.type_of(param.def_id).instantiate(tcx, preceding_args).into() } else { // If no type arguments were provided, we have to infer them. // This case also occurs as a result of some malformed input, e.g. @@ -1353,7 +1367,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if !infer_args { return tcx .const_param_default(param.def_id) - .instantiate(tcx, args.unwrap()) + .instantiate(tcx, preceding_args) .into(); } } @@ -1412,11 +1426,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { - self.dcx().span_delayed_bug( + self.dcx().span_bug( span, format!( - "instantiate_value_path: (UFCS) {self_ty:?} was a subtype of {impl_ty:?} but now is not?", - ), + "instantiate_value_path: (UFCS) {self_ty:?} was a subtype of {impl_ty:?} but now is not?", + ), ); } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index afba812a8e7..f02b0f95390 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -15,7 +15,7 @@ use hir::def_id::CRATE_DEF_ID; use rustc_errors::DiagCtxt; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; +use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; use rustc_infer::infer; use rustc_infer::infer::error_reporting::sub_relations::SubRelations; use rustc_infer::infer::error_reporting::TypeErrCtxt; @@ -213,25 +213,21 @@ impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { } } -impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { +impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } - fn item_def_id(&self) -> DefId { - self.body_id.to_def_id() + fn item_def_id(&self) -> LocalDefId { + self.body_id } - fn allow_infer(&self) -> bool { - true - } - - fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> { - let v = match def { - Some(def) => infer::RegionParameterDefinition(span, def.name), - None => infer::MiscVariable(span), + fn re_infer(&self, span: Span, reason: RegionInferReason<'_>) -> ty::Region<'tcx> { + let v = match reason { + RegionInferReason::Param(def) => infer::RegionParameterDefinition(span, def.name), + _ => infer::MiscVariable(span), }; - Some(self.next_region_var(v)) + self.next_region_var(v) } fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { @@ -241,12 +237,7 @@ impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> { } } - fn ct_infer( - &self, - ty: Ty<'tcx>, - param: Option<&ty::GenericParamDef>, - span: Span, - ) -> Const<'tcx> { + fn ct_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> { // FIXME ideally this shouldn't use unwrap match param { Some( @@ -256,7 +247,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, span), + None => self.next_const_var(span), } } @@ -350,6 +341,22 @@ impl<'a, 'tcx> HirTyLowerer<'tcx> for FnCtxt<'a, 'tcx> { fn set_tainted_by_errors(&self, e: ErrorGuaranteed) { self.infcx.set_tainted_by_errors(e) } + + fn lower_fn_sig( + &self, + decl: &rustc_hir::FnDecl<'tcx>, + _generics: Option<&rustc_hir::Generics<'_>>, + _hir_id: rustc_hir::HirId, + _hir_ty: Option<&hir::Ty<'_>>, + ) -> (Vec<Ty<'tcx>>, Ty<'tcx>) { + let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_arg_ty(a, None)).collect(); + + let output_ty = match decl.output { + hir::FnRetTy::Return(output) => self.lowerer().lower_ty(output), + hir::FnRetTy::DefaultReturn(..) => self.tcx().types.unit, + }; + (input_tys, output_ty) + } } /// The `ty` representation of a user-provided type. Depending on the use-site diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 5723b73a328..9ab89f3444c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -22,7 +22,6 @@ use rustc_hir::{ }; use rustc_hir_analysis::collect::suggest_impl_trait; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; -use rustc_infer::traits; use rustc_middle::lint::in_external_macro; use rustc_middle::middle::stability::EvalResult; use rustc_middle::span_bug; @@ -36,6 +35,7 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, Symbol}; use rustc_trait_selection::infer::InferCtxtExt; +use rustc_trait_selection::traits; use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt; use rustc_trait_selection::traits::error_reporting::DefIdOrName; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -1051,10 +1051,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .take_while(|(_, node)| { // look at parents until we find the first body owner node.body_id().is_none() - && !matches!( - node, - Node::Expr(Expr { kind: ExprKind::ConstBlock { .. }, .. }) - ) }) .any(|(parent_id, _)| self.is_loop(parent_id)); diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 9c64f9475cf..3c9a49e91a3 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -7,7 +7,9 @@ use rustc_hir::GenericArg; use rustc_hir_analysis::hir_ty_lowering::generics::{ check_generic_arg_count_for_call, lower_generic_args, }; -use rustc_hir_analysis::hir_ty_lowering::{GenericArgsLowerer, HirTyLowerer, IsMethodCall}; +use rustc_hir_analysis::hir_ty_lowering::{ + GenericArgsLowerer, HirTyLowerer, IsMethodCall, RegionInferReason, +}; use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk}; use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; @@ -383,13 +385,17 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { fn provided_kind( &mut self, + _preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { match (¶m.kind, arg) { - (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - self.cfcx.fcx.lowerer().lower_lifetime(lt, Some(param)).into() - } + (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => self + .cfcx + .fcx + .lowerer() + .lower_lifetime(lt, RegionInferReason::Param(param)) + .into(), (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { self.cfcx.lower_ty(ty).raw.into() } @@ -400,16 +406,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.cfcx.ty_infer(Some(param), inf.span).into() } (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { - let tcx = self.cfcx.tcx(); - self.cfcx - .ct_infer( - tcx.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), - Some(param), - inf.span, - ) - .into() + self.cfcx.ct_infer(Some(param), inf.span).into() } (kind, arg) => { bug!("mismatched method arg kind {kind:?} in turbofish: {arg:?}") @@ -419,7 +416,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { fn inferred_kind( &mut self, - _args: Option<&[ty::GenericArg<'tcx>]>, + _preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, _infer_args: bool, ) -> ty::GenericArg<'tcx> { diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 4165ccb1b80..1f90d5e4c88 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -7,7 +7,6 @@ mod prelude_edition_lints; pub mod probe; mod suggest; -pub use self::suggest::SelfSource; pub use self::MethodError::*; use crate::FnCtxt; diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 97a74b55c53..e842bba34bf 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -41,6 +41,7 @@ use rustc_trait_selection::traits::query::method_autoderef::{ use rustc_trait_selection::traits::query::CanonicalTyGoal; use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{self, ObligationCause}; +use std::cell::Cell; use std::cell::RefCell; use std::cmp::max; use std::iter; @@ -76,8 +77,12 @@ pub(crate) struct ProbeContext<'a, 'tcx> { /// requested name (by edit distance) allow_similar_names: bool, + /// List of potential private candidates. Will be trimmed to ones that + /// actually apply and then the result inserted into `private_candidate` + private_candidates: Vec<Candidate<'tcx>>, + /// Some(candidate) if there is a private candidate - private_candidate: Option<(DefKind, DefId)>, + private_candidate: Cell<Option<(DefKind, DefId)>>, /// Collects near misses when the candidate functions are missing a `self` keyword and is only /// used for error reporting @@ -301,7 +306,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self_ty: Ty<'tcx>, scope_expr_id: HirId, scope: ProbeScope, - ) -> Vec<Candidate<'tcx>> { + ) -> Result<Vec<Candidate<'tcx>>, MethodError<'tcx>> { self.probe_op( item_name.span, mode, @@ -319,7 +324,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect()) }, ) - .unwrap() } pub(crate) fn probe_op<OP, R>( @@ -581,7 +585,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { orig_steps_var_values, steps, allow_similar_names: false, - private_candidate: None, + private_candidates: Vec::new(), + private_candidate: Cell::new(None), static_candidates: RefCell::new(Vec::new()), unsatisfied_predicates: RefCell::new(Vec::new()), scope_expr_id, @@ -593,7 +598,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.inherent_candidates.clear(); self.extension_candidates.clear(); self.impl_dups.clear(); - self.private_candidate = None; + self.private_candidates.clear(); + self.private_candidate.set(None); self.static_candidates.borrow_mut().clear(); self.unsatisfied_predicates.borrow_mut().clear(); } @@ -617,9 +623,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } else { self.extension_candidates.push(candidate); } - } else if self.private_candidate.is_none() { - self.private_candidate = - Some((candidate.item.kind.as_def_kind(), candidate.item.def_id)); + } else { + self.private_candidates.push(candidate); } } @@ -1171,7 +1176,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let mut possibly_unsatisfied_predicates = Vec::new(); for (kind, candidates) in - &[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)] + [("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)] { debug!("searching {} candidates", kind); let res = self.consider_candidates( @@ -1185,6 +1190,14 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } + if self.private_candidate.get().is_none() { + if let Some(Ok(pick)) = + self.consider_candidates(self_ty, &self.private_candidates, &mut vec![], None) + { + self.private_candidate.set(Some((pick.item.kind.as_def_kind(), pick.item.def_id))); + } + } + // `pick_method` may be called twice for the same self_ty if no stable methods // match. Only extend once. if unstable_candidates.is_some() { @@ -1390,7 +1403,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let mut result = ProbeResult::Match; let cause = &self.misc(self.span); - let ocx = ObligationCtxt::new(self); + let ocx = ObligationCtxt::new_with_diagnostics(self); let mut trait_predicate = None; let (mut xform_self_ty, mut xform_ret_ty); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index daaaf630f2c..bbe4a8791c6 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -16,11 +16,11 @@ use rustc_data_structures::unord::UnordSet; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, Diag, MultiSpan, StashKey, }; -use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_hir::PathSegment; +use rustc_hir::{self as hir, HirId}; use rustc_hir::{ExprKind, Node, QPath}; use rustc_infer::infer::{self, RegionVariableOrigin}; use rustc_middle::bug; @@ -187,37 +187,56 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self))] pub fn report_method_error( &self, - span: Span, - rcvr_opt: Option<&'tcx hir::Expr<'tcx>>, + call_id: HirId, rcvr_ty: Ty<'tcx>, - item_name: Ident, - expr_id: hir::HirId, - source: SelfSource<'tcx>, error: MethodError<'tcx>, - args: Option<&'tcx [hir::Expr<'tcx>]>, expected: Expectation<'tcx>, trait_missing_method: bool, ) -> Option<Diag<'_>> { + let (span, sugg_span, source, item_name, args) = match self.tcx.hir_node(call_id) { + hir::Node::Expr(&hir::Expr { + kind: hir::ExprKind::MethodCall(segment, rcvr, args, _), + span, + .. + }) => { + (segment.ident.span, span, SelfSource::MethodCall(rcvr), segment.ident, Some(args)) + } + hir::Node::Expr(&hir::Expr { + kind: hir::ExprKind::Path(QPath::TypeRelative(rcvr, segment)), + span, + .. + }) + | hir::Node::Pat(&hir::Pat { + kind: + hir::PatKind::Path(QPath::TypeRelative(rcvr, segment)) + | hir::PatKind::Struct(QPath::TypeRelative(rcvr, segment), ..) + | hir::PatKind::TupleStruct(QPath::TypeRelative(rcvr, segment), ..), + span, + .. + }) => { + let args = match self.tcx.parent_hir_node(call_id) { + hir::Node::Expr(&hir::Expr { + kind: hir::ExprKind::Call(callee, args), .. + }) if callee.hir_id == call_id => Some(args), + _ => None, + }; + (segment.ident.span, span, SelfSource::QPath(rcvr), segment.ident, args) + } + node => unreachable!("{node:?}"), + }; + // Avoid suggestions when we don't know what's going on. if rcvr_ty.references_error() { return None; } - let sugg_span = if let SelfSource::MethodCall(expr) = source { - // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing. - self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id)).span - } else { - span - }; - match error { MethodError::NoMatch(mut no_match_data) => { return self.report_no_match_method_error( span, - rcvr_opt, rcvr_ty, item_name, - expr_id, + call_id, source, args, sugg_span, @@ -362,7 +381,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn suggest_use_shadowed_binding_with_method( &self, - rcvr_opt: Option<&'tcx hir::Expr<'tcx>>, + self_source: SelfSource<'tcx>, method_name: Ident, ty_str_reported: &str, err: &mut Diag<'_>, @@ -502,7 +521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - if let Some(rcvr) = rcvr_opt + if let SelfSource::MethodCall(rcvr) = self_source && let hir::ExprKind::Path(QPath::Resolved(_, path)) = rcvr.kind && let hir::def::Res::Local(recv_id) = path.res && let Some(segment) = path.segments.first() @@ -548,7 +567,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn report_no_match_method_error( &self, mut span: Span, - rcvr_opt: Option<&'tcx hir::Expr<'tcx>>, rcvr_ty: Ty<'tcx>, item_name: Ident, expr_id: hir::HirId, @@ -658,7 +676,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if is_method { self.suggest_use_shadowed_binding_with_method( - rcvr_opt, + source, item_name, &ty_str_reported, &mut err, @@ -1622,10 +1640,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .unwrap_or(Ty::new_misc_error(self.tcx)), ); - // FIXME: `probe_for_name_many` searches for methods in inherent implementations, - // so it may return a candidate that doesn't belong to this `revr_ty`. We need to - // check whether the instantiated type matches the received one. - for _matched_method in self.probe_for_name_many( + let Ok(candidates) = self.probe_for_name_many( Mode::MethodCall, item_name, None, @@ -1633,7 +1648,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcvr_ty, source_expr.hir_id, ProbeScope::TraitsInScope, - ) { + ) else { + return; + }; + + // FIXME: `probe_for_name_many` searches for methods in inherent implementations, + // so it may return a candidate that doesn't belong to this `revr_ty`. We need to + // check whether the instantiated type matches the received one. + for _matched_method in candidates { // found a match, push to stack stack_methods.push(rcvr_ty); } @@ -2078,9 +2100,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP)) .into(), GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(), - GenericArgKind::Const(arg) => { - self.next_const_var(arg.ty(), DUMMY_SP).into() - } + GenericArgKind::Const(_) => self.next_const_var(DUMMY_SP).into(), } } else { arg diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 25b74dca12f..d774ae2146a 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -928,7 +928,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (obligation, _) = self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types)); // FIXME: This should potentially just add the obligation to the `FnCtxt` - let ocx = ObligationCtxt::new(&self.infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&self.infcx); ocx.register_obligation(obligation); Err(ocx.select_all_or_error()) } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index b37aba38619..9476dc70483 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -12,7 +12,7 @@ use rustc_infer::infer; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; -use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; +use rustc_session::{lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS, parse::feature_err}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Spanned; @@ -223,9 +223,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info; let path_res = match &pat.kind { - PatKind::Path(qpath) => Some( - self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None), - ), + PatKind::Path(qpath) => { + Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span)) + } _ => None, }; let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res)); @@ -335,9 +335,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match adjust_mode { AdjustMode::Pass => (expected, def_br, max_ref_mutbl), AdjustMode::Reset => (expected, ByRef::No, MutblCap::Mut), - AdjustMode::Peel => { - self.peel_off_references(pat, expected, def_br, Mutability::Mut, max_ref_mutbl) - } + AdjustMode::Peel => self.peel_off_references(pat, expected, def_br, max_ref_mutbl), } } @@ -408,8 +406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, mut def_br: ByRef, - max_peelable_mutability: Mutability, - mut max_ref_mutability: MutblCap, + mut max_ref_mutbl: 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, @@ -421,9 +418,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // See the examples in `ui/match-defbm*.rs`. let mut pat_adjustments = vec![]; - while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() - && inner_mutability <= max_peelable_mutability - { + while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() { debug!("inspecting {:?}", expected); debug!("current discriminant is Ref, inserting implicit deref"); @@ -443,10 +438,10 @@ 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.as_mutbl()); + if self.tcx.features().ref_pat_eat_one_layer_2024 { + def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl()); if def_br == ByRef::Yes(Mutability::Not) { - max_ref_mutability = MutblCap::Not; + max_ref_mutbl = MutblCap::Not; } } @@ -458,7 +453,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .insert(pat.hir_id, pat_adjustments); } - (expected, def_br, max_ref_mutability) + (expected, def_br, max_ref_mutbl) } fn check_pat_lit( @@ -674,17 +669,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Determine the binding mode... 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(_)) => - { - 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, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => { + if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 { + if !self.tcx.features().mut_ref { + feature_err( + &self.tcx.sess, + sym::mut_ref, + pat.span.until(ident.span), + "binding cannot be both mutable and by-reference", + ) + .emit(); + } + + BindingMode(def_br, Mutability::Mut) + } else { + // `mut` resets binding mode on edition <= 2021 + 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(_), _) => user_bind_annot, @@ -1184,7 +1189,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Resolve the path and check the definition for errors. let (res, opt_ty, segments) = - self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None); + self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span); if res == Res::Err { let e = tcx.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted"); self.set_tainted_by_errors(e); @@ -2126,57 +2131,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mut expected: Ty<'tcx>, mut pat_info: PatInfo<'tcx, '_>, ) -> Ty<'tcx> { - // 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 no_ref_mut_behind_and = self.tcx.features().ref_pat_eat_one_layer_2024; + let new_match_ergonomics = pat.span.at_least_rust_2024() && no_ref_mut_behind_and; - 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 pat_prefix_span = + inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end)); - let mut inherited_ref_mutbl_match = false; - if match_ergonomics_mode != MatchErgonomicsMode::Legacy { + if no_ref_mut_behind_and { 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)), - ); + pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span); } + } else { + pat_info.max_ref_mutbl = MutblCap::Mut; + } + if new_match_ergonomics { if let ByRef::Yes(inh_mut) = pat_info.binding_mode { - inherited_ref_mutbl_match = pat_mutbl <= inh_mut; - } + // ref pattern consumes inherited reference + + if pat_mutbl > inh_mut { + // Tried to match inherited `ref` with `&mut`, which is an error + let err_msg = "cannot match inherited `&` with `&mut` pattern"; + let err = if let Some(span) = pat_prefix_span { + let mut err = self.dcx().struct_span_err(span, err_msg); + err.span_suggestion_verbose( + span, + "replace this `&mut` pattern with `&`", + "&", + Applicability::MachineApplicable, + ); + err + } else { + self.dcx().struct_span_err(pat.span, err_msg) + }; + err.emit(); + } - 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; + self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); + self.check_pat(inner, expected, pat_info); + return expected; } } else { // Reset binding mode on old editions @@ -2189,8 +2184,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .rust_2024_migration_desugared_pats_mut() .insert(pat_info.top_info.hir_id); } - - pat_info.max_ref_mutbl = MutblCap::Mut; } let tcx = self.tcx; @@ -2205,34 +2198,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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 - { + ty::Ref(_, r_ty, r_mutbl) + if (new_match_ergonomics && r_mutbl >= pat_mutbl) + || r_mutbl == pat_mutbl => + { + if no_ref_mut_behind_and && r_mutbl == Mutability::Not { 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); @@ -2409,10 +2385,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { min_len: u64, ) -> (Option<Ty<'tcx>>, Ty<'tcx>) { let len = match len.eval(self.tcx, self.param_env, span) { - Ok(val) => val + Ok((_, val)) => val .try_to_scalar() - .and_then(|scalar| scalar.try_to_int().ok()) - .and_then(|int| int.try_to_target_usize(self.tcx).ok()), + .and_then(|scalar| scalar.try_to_scalar_int().ok()) + .map(|int| int.to_target_usize(self.tcx)), Err(ErrorHandled::Reported(..)) => { let guar = self.error_scrutinee_unfixed_length(span); return (Some(Ty::new_error(self.tcx, guar)), arr_ty); diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index 19d6481cc1b..28745af3a53 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -11,7 +11,9 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefIdMap; use rustc_span::Span; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use rustc_trait_selection::traits::{self, PredicateObligation, TraitEngine, TraitEngineExt as _}; +use rustc_trait_selection::traits::{ + self, FulfillmentError, PredicateObligation, TraitEngine, TraitEngineExt as _, +}; use std::cell::RefCell; use std::ops::Deref; @@ -34,7 +36,7 @@ pub(crate) struct TypeckRootCtxt<'tcx> { pub(super) locals: RefCell<HirIdMap<Ty<'tcx>>>, - pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx>>>, + pub(super) fulfillment_cx: RefCell<Box<dyn TraitEngine<'tcx, FulfillmentError<'tcx>>>>, /// Some additional `Sized` obligations badly affect type inference. /// These obligations are added in a later stage of typeck. @@ -83,7 +85,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> { TypeckRootCtxt { typeck_results, - fulfillment_cx: RefCell::new(<dyn TraitEngine<'_>>::new(&infcx)), + fulfillment_cx: RefCell::new(<dyn TraitEngine<'_, _>>::new(&infcx)), infcx, locals: RefCell::new(Default::default()), deferred_sized_obligations: RefCell::new(Vec::new()), @@ -158,7 +160,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> { { // If the projection predicate (Foo::Bar == X) has X as a non-TyVid, // we need to make it into one. - if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) { + if let Some(vid) = predicate.term.as_type().and_then(|ty| ty.ty_vid()) { debug!("infer_var_info: {:?}.output = true", vid); infer_var_info.entry(vid).or_default().output = true; } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 4386e68ce86..466397817da 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -149,6 +149,10 @@ impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> { self.visit_body(body); self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, capture_clause); } + hir::ExprKind::ConstBlock(anon_const) => { + let body = self.fcx.tcx.hir().body(anon_const.body); + self.visit_body(body); + } _ => {} } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index e337105f011..b67d29fce92 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -3,7 +3,6 @@ // generic parameters. use crate::FnCtxt; -use hir::def::DefKind; use rustc_data_structures::unord::ExtendUnord; use rustc_errors::{ErrorGuaranteed, StashKey}; use rustc_hir as hir; @@ -17,7 +16,7 @@ use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::TypeSuperFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_span::symbol::{kw, sym}; +use rustc_span::symbol::sym; use rustc_span::Span; use rustc_trait_selection::solve; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; @@ -296,11 +295,11 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => { self.visit_field_id(e.hir_id); } - hir::ExprKind::ConstBlock(_) => { - let feed = self.tcx().create_def(self.fcx.body_id, kw::Empty, DefKind::InlineConst); - feed.def_span(e.span); - feed.local_def_id_to_hir_id(e.hir_id); - self.typeck_results.inline_consts.insert(e.hir_id.local_id, feed.def_id()); + hir::ExprKind::ConstBlock(anon_const) => { + self.visit_node_id(e.span, anon_const.hir_id); + + let body = self.tcx().hir().body(anon_const.body); + self.visit_body(body); } _ => {} } @@ -863,7 +862,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> { fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { self.handle_term(ct, ty::Const::outer_exclusive_binder, |tcx, guar| { - ty::Const::new_error(tcx, guar, ct.ty()) + ty::Const::new_error(tcx, guar) }) .super_fold_with(self) } diff --git a/compiler/rustc_index_macros/Cargo.toml b/compiler/rustc_index_macros/Cargo.toml index c4ca29db3c2..07ee81788ce 100644 --- a/compiler/rustc_index_macros/Cargo.toml +++ b/compiler/rustc_index_macros/Cargo.toml @@ -7,11 +7,10 @@ edition = "2021" proc-macro = true [dependencies] -synstructure = "0.13.0" syn = { version = "2.0.9", features = ["full"] } proc-macro2 = "1" quote = "1" [features] default = ["nightly"] -nightly = [] \ No newline at end of file +nightly = [] diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index c1565a7d40f..5136ab79a0f 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -18,6 +18,7 @@ rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } +rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 17e6d6250ad..046d908d148 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -27,8 +27,8 @@ use super::*; +use crate::infer::relate::{Relate, StructurallyRelateAliases, TypeRelation}; use rustc_middle::bug; -use rustc_middle::ty::relate::{Relate, TypeRelation}; use rustc_middle::ty::{Const, ImplSubject}; /// Whether we should define opaque types or just treat them opaquely. @@ -90,7 +90,7 @@ impl<'tcx> InferCtxt<'tcx> { } } -pub trait ToTrace<'tcx>: Relate<'tcx> + Copy { +pub trait ToTrace<'tcx>: Relate<TyCtxt<'tcx>> + Copy { fn to_trace( cause: &ObligationCause<'tcx>, a_is_expected: bool, diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 27b06c4b73e..bc2592b43f3 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -462,7 +462,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { // any equated inference vars correctly! let root_vid = self.infcx.unwrap().root_const_var(vid); if root_vid != vid { - ct = ty::Const::new_var(self.tcx, root_vid, ct.ty()); + ct = ty::Const::new_var(self.tcx, root_vid); vid = root_vid; } @@ -481,7 +481,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { ui = ty::UniverseIndex::ROOT; } return self.canonicalize_const_var( - CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty()) }, + CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) }, ct, ); } @@ -510,9 +510,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { } ty::ConstKind::Placeholder(placeholder) => { return self.canonicalize_const_var( - CanonicalVarInfo { - kind: CanonicalVarKind::PlaceholderConst(placeholder, ct.ty()), - }, + CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderConst(placeholder) }, ct, ); } @@ -719,9 +717,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { CanonicalVarKind::Region(u) => { CanonicalVarKind::Region(reverse_universe_map[&u]) } - CanonicalVarKind::Const(u, t) => { - CanonicalVarKind::Const(reverse_universe_map[&u], t) - } + CanonicalVarKind::Const(u) => CanonicalVarKind::Const(reverse_universe_map[&u]), CanonicalVarKind::PlaceholderTy(placeholder) => { CanonicalVarKind::PlaceholderTy(ty::Placeholder { universe: reverse_universe_map[&placeholder.universe], @@ -734,14 +730,11 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { ..placeholder }) } - CanonicalVarKind::PlaceholderConst(placeholder, t) => { - CanonicalVarKind::PlaceholderConst( - ty::Placeholder { - universe: reverse_universe_map[&placeholder.universe], - ..placeholder - }, - t, - ) + CanonicalVarKind::PlaceholderConst(placeholder) => { + CanonicalVarKind::PlaceholderConst(ty::Placeholder { + universe: reverse_universe_map[&placeholder.universe], + ..placeholder + }) } }, }) @@ -806,6 +799,6 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { !self.infcx.is_some_and(|infcx| const_var != infcx.shallow_resolve_const(const_var)) ); let var = self.canonical_var(info, const_var.into()); - ty::Const::new_bound(self.tcx, self.binder_index, var, self.fold_ty(const_var.ty())) + ty::Const::new_bound(self.tcx, self.binder_index, var) } } diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index de0e15ef3de..153de3d4c09 100644 --- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -70,7 +70,7 @@ where GenericArgKind::Type(ty) => ty, r => bug!("{:?} is a type but value is {:?}", bound_ty, r), }, - consts: &mut |bound_ct: ty::BoundVar, _| match var_values[bound_ct].unpack() { + consts: &mut |bound_ct: ty::BoundVar| match var_values[bound_ct].unpack() { GenericArgKind::Const(ct) => ct, c => bug!("{:?} is a const but value is {:?}", bound_ct, c), }, diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index 1abb8086d41..8ad4f7926ca 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -143,8 +143,8 @@ impl<'tcx> InferCtxt<'tcx> { ty::Region::new_placeholder(self.tcx, placeholder_mapped).into() } - CanonicalVarKind::Const(ui, ty) => { - self.next_const_var_in_universe(ty, span, universe_map(ui)).into() + CanonicalVarKind::Const(ui) => { + self.next_const_var_in_universe(span, universe_map(ui)).into() } CanonicalVarKind::Effect => { let vid = self @@ -153,13 +153,12 @@ impl<'tcx> InferCtxt<'tcx> { .effect_unification_table() .new_key(EffectVarValue::Unknown) .vid; - ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid), self.tcx.types.bool) - .into() + ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(vid)).into() } - CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }, ty) => { + CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, bound }) => { let universe_mapped = universe_map(universe); let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, bound }; - ty::Const::new_placeholder(self.tcx, placeholder_mapped, ty).into() + ty::Const::new_placeholder(self.tcx, placeholder_mapped).into() } } } diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 1732913e191..d7dd6a1e7cf 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -16,7 +16,7 @@ use crate::infer::region_constraints::{Constraint, RegionConstraintData}; use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult}; use crate::traits::query::NoSolution; use crate::traits::{Obligation, ObligationCause, PredicateObligation}; -use crate::traits::{TraitEngine, TraitEngineExt}; +use crate::traits::{ScrubbedTraitError, TraitEngine}; use rustc_data_structures::captures::Captures; use rustc_index::Idx; use rustc_index::IndexVec; @@ -54,7 +54,7 @@ impl<'tcx> InferCtxt<'tcx> { &self, inference_vars: CanonicalVarValues<'tcx>, answer: T, - fulfill_cx: &mut dyn TraitEngine<'tcx>, + fulfill_cx: &mut dyn TraitEngine<'tcx, ScrubbedTraitError<'tcx>>, ) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution> where T: Debug + TypeFoldable<TyCtxt<'tcx>>, @@ -101,7 +101,7 @@ impl<'tcx> InferCtxt<'tcx> { &self, inference_vars: CanonicalVarValues<'tcx>, answer: T, - fulfill_cx: &mut dyn TraitEngine<'tcx>, + fulfill_cx: &mut dyn TraitEngine<'tcx, ScrubbedTraitError<'tcx>>, ) -> Result<QueryResponse<'tcx, T>, NoSolution> where T: Debug + TypeFoldable<TyCtxt<'tcx>>, @@ -109,19 +109,13 @@ impl<'tcx> InferCtxt<'tcx> { let tcx = self.tcx; // Select everything, returning errors. - let true_errors = fulfill_cx.select_where_possible(self); - debug!("true_errors = {:#?}", true_errors); + let errors = fulfill_cx.select_all_or_error(self); - if !true_errors.is_empty() { - // FIXME -- we don't indicate *why* we failed to solve - debug!("make_query_response: true_errors={:#?}", true_errors); + // True error! + if errors.iter().any(|e| e.is_true_error()) { return Err(NoSolution); } - // Anything left unselected *now* must be an ambiguity. - let ambig_errors = fulfill_cx.select_all_or_error(self); - debug!("ambig_errors = {:#?}", ambig_errors); - let region_obligations = self.take_registered_region_obligations(); debug!(?region_obligations); let region_constraints = self.with_region_constraints(|region_constraints| { @@ -135,8 +129,7 @@ impl<'tcx> InferCtxt<'tcx> { }); debug!(?region_constraints); - let certainty = - if ambig_errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous }; + let certainty = if errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous }; let opaque_types = self.take_opaque_types_for_query_response(); diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 95fbc1e66ce..ed483c6cbeb 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -58,6 +58,7 @@ use crate::traits::{ PredicateObligation, }; +use crate::infer::relate::{self, RelateResult, TypeRelation}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, Diag, DiagCtxt, DiagStyledString, @@ -71,8 +72,8 @@ use rustc_hir::lang_items::LangItem; use rustc_macros::extension; use rustc_middle::bug; use rustc_middle::dep_graph::DepContext; +use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError, PrintTraitRefExt as _}; -use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; use rustc_middle::ty::Upcast; use rustc_middle::ty::{ self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable, @@ -425,7 +426,7 @@ impl<'tcx> InferCtxt<'tcx> { ty::ClauseKind::Projection(projection_predicate) if projection_predicate.projection_term.def_id == item_def_id => { - projection_predicate.term.ty() + projection_predicate.term.as_type() } _ => None, }) @@ -2686,7 +2687,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { /// with the other type. A TyVar inference type is compatible with any type, and an IntVar or /// FloatVar inference type are compatible with themselves or their concrete types (Int and /// Float types, respectively). When comparing two ADTs, these rules apply recursively. - pub fn same_type_modulo_infer<T: relate::Relate<'tcx>>(&self, a: T, b: T) -> bool { + pub fn same_type_modulo_infer<T: relate::Relate<TyCtxt<'tcx>>>(&self, a: T, b: T) -> bool { let (a, b) = self.resolve_vars_if_possible((a, b)); SameTypeModuloInfer(self).relate(a, b).is_ok() } @@ -2694,7 +2695,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { struct SameTypeModuloInfer<'a, 'tcx>(&'a InferCtxt<'tcx>); -impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { +impl<'tcx> TypeRelation<TyCtxt<'tcx>> for SameTypeModuloInfer<'_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.0.tcx } @@ -2703,10 +2704,10 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { "SameTypeModuloInfer" } - fn relate_with_variance<T: relate::Relate<'tcx>>( + fn relate_with_variance<T: relate::Relate<TyCtxt<'tcx>>>( &mut self, _variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, + _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, a: T, b: T, ) -> relate::RelateResult<'tcx, T> { @@ -2754,7 +2755,7 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { b: ty::Binder<'tcx, T>, ) -> relate::RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: relate::Relate<'tcx>, + T: relate::Relate<TyCtxt<'tcx>>, { Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) } 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 fb8c843f309..cb0e13652e8 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 @@ -543,9 +543,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { match arg.unpack() { GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(), - GenericArgKind::Const(arg) => { - self.next_const_var(arg.ty(), DUMMY_SP).into() - } + GenericArgKind::Const(_) => self.next_const_var(DUMMY_SP).into(), } })) .unwrap(); 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 19ef2d61fca..effb4090692 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 @@ -21,18 +21,26 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { sp: Span, body_owner_def_id: DefId, ) { - use ty::error::TypeError::*; debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause); let tcx = self.tcx; match err { - ArgumentSorts(values, _) | Sorts(values) => { + TypeError::ArgumentSorts(values, _) | TypeError::Sorts(values) => { match (*values.expected.kind(), *values.found.kind()) { (ty::Closure(..), ty::Closure(..)) => { diag.note("no two closures, even if identical, have the same type"); diag.help("consider boxing your closure and/or using it as a trait object"); } + (ty::Coroutine(def_id1, ..), ty::Coroutine(def_id2, ..)) + if self.tcx.coroutine_is_async(def_id1) + && self.tcx.coroutine_is_async(def_id2) => + { + diag.note("no two async blocks, even if identical, have the same type"); + diag.help( + "consider pinning your async block and casting it to a trait object", + ); + } (ty::Alias(ty::Opaque, ..), ty::Alias(ty::Opaque, ..)) => { // Issue #63167 diag.note("distinct uses of `impl Trait` result in different opaque types"); @@ -483,7 +491,7 @@ impl<T> Trait<T> for X { values.found.kind(), ); } - CyclicTy(ty) => { + TypeError::CyclicTy(ty) => { // Watch out for various cases of cyclic types and try to explain. if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() { diag.note( @@ -494,7 +502,7 @@ impl<T> Trait<T> for X { ); } } - TargetFeatureCast(def_id) => { + TypeError::TargetFeatureCast(def_id) => { let target_spans = tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span); diag.note( "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers" diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index b2d89523ea8..4bb59bd9037 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -33,7 +33,6 @@ use super::InferCtxt; use rustc_data_structures::fx::FxHashMap; use rustc_middle::bug; -use rustc_middle::infer::unify_key::ToType; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitableExt}; use std::collections::hash_map::Entry; @@ -80,7 +79,6 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { &mut self, input: Result<ty::Const<'tcx>, ty::InferConst>, freshener: F, - ty: Ty<'tcx>, ) -> ty::Const<'tcx> where F: FnOnce(u32) -> ty::InferConst, @@ -92,7 +90,7 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { Entry::Vacant(entry) => { let index = self.const_freshen_count; self.const_freshen_count += 1; - let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index), ty); + let ct = ty::Const::new_infer(self.infcx.tcx, freshener(index)); entry.insert(ct); ct } @@ -150,7 +148,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> { ty::InferConst::Var(inner.const_unification_table().find(v).vid) }); drop(inner); - self.freshen_const(input, ty::InferConst::Fresh, ct.ty()) + self.freshen_const(input, ty::InferConst::Fresh) } ty::ConstKind::Infer(ty::InferConst::EffectVar(v)) => { let mut inner = self.infcx.inner.borrow_mut(); @@ -159,7 +157,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> { ty::InferConst::EffectVar(inner.effect_unification_table().find(v).vid) }); drop(inner); - self.freshen_const(input, ty::InferConst::Fresh, ct.ty()) + self.freshen_const(input, ty::InferConst::Fresh) } ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => { if i >= self.const_freshen_count { @@ -178,7 +176,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> { } ty::ConstKind::Param(_) - | ty::ConstKind::Value(_) + | ty::ConstKind::Value(_, _) | ty::ConstKind::Unevaluated(..) | ty::ConstKind::Expr(..) | ty::ConstKind::Error(_) => ct.super_fold_with(self), @@ -204,22 +202,27 @@ impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { ty::IntVar(v) => { let mut inner = self.infcx.inner.borrow_mut(); - let input = inner - .int_unification_table() - .probe_value(v) - .map(|v| v.to_type(self.infcx.tcx)) - .ok_or_else(|| ty::IntVar(inner.int_unification_table().find(v))); + let value = inner.int_unification_table().probe_value(v); + let input = match value { + ty::IntVarValue::IntType(ty) => Ok(Ty::new_int(self.infcx.tcx, ty)), + ty::IntVarValue::UintType(ty) => Ok(Ty::new_uint(self.infcx.tcx, ty)), + ty::IntVarValue::Unknown => { + Err(ty::IntVar(inner.int_unification_table().find(v))) + } + }; drop(inner); Some(self.freshen_ty(input, |n| Ty::new_fresh_int(self.infcx.tcx, n))) } ty::FloatVar(v) => { let mut inner = self.infcx.inner.borrow_mut(); - let input = inner - .float_unification_table() - .probe_value(v) - .map(|v| v.to_type(self.infcx.tcx)) - .ok_or_else(|| ty::FloatVar(inner.float_unification_table().find(v))); + let value = inner.float_unification_table().probe_value(v); + let input = match value { + ty::FloatVarValue::Known(ty) => Ok(Ty::new_float(self.infcx.tcx, ty)), + ty::FloatVarValue::Unknown => { + Err(ty::FloatVar(inner.float_unification_table().find(v))) + } + }; drop(inner); Some(self.freshen_ty(input, |n| Ty::new_fresh_float(self.infcx.tcx, n))) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c8bb6cf5f9b..c606ab808ef 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1,9 +1,6 @@ pub use at::DefineOpaqueTypes; pub use freshen::TypeFreshener; pub use lexical_region_resolve::RegionResolutionError; -pub use relate::combine::CombineFields; -pub use relate::combine::ObligationEmittingRelation; -pub use relate::StructurallyRelateAliases; pub use rustc_macros::{TypeFoldable, TypeVisitable}; pub use rustc_middle::ty::IntVarValue; pub use BoundRegionConversionTime::*; @@ -11,8 +8,9 @@ pub use RegionVariableOrigin::*; pub use SubregionOrigin::*; pub use ValuePairs::*; +use crate::infer::relate::{CombineFields, RelateResult}; use crate::traits::{ - self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine, TraitEngineExt, + self, ObligationCause, ObligationInspector, PredicateObligations, TraitEngine, }; use error_reporting::TypeErrCtxt; use free_regions::RegionRelations; @@ -29,9 +27,9 @@ use rustc_errors::{Diag, DiagCtxt, ErrorGuaranteed}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::extension; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; +use rustc_middle::infer::unify_key::ConstVariableOrigin; use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::infer::unify_key::EffectVarValue; -use rustc_middle::infer::unify_key::{ConstVariableOrigin, ToType}; use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::mir::ConstraintCategory; @@ -39,9 +37,8 @@ use rustc_middle::traits::select; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BoundVarReplacerDelegate; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; -use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::{self, GenericParamDefKind, InferConst, InferTy, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt}; use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid}; use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef}; use rustc_middle::{bug, span_bug}; @@ -62,7 +59,7 @@ pub mod opaque_types; pub mod outlives; mod projection; pub mod region_constraints; -mod relate; +pub mod relate; pub mod resolve; pub(crate) mod snapshot; pub mod type_variable; @@ -392,18 +389,18 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { self.opportunistic_resolve_float_var(vid) } - fn opportunistic_resolve_ct_var(&self, vid: ConstVid, ty: Ty<'tcx>) -> ty::Const<'tcx> { + fn opportunistic_resolve_ct_var(&self, vid: ConstVid) -> ty::Const<'tcx> { match self.probe_const_var(vid) { Ok(ct) => ct, - Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid), ty), + Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid)), } } - fn opportunistic_resolve_effect_var(&self, vid: EffectVid, ty: Ty<'tcx>) -> ty::Const<'tcx> { + fn opportunistic_resolve_effect_var(&self, vid: EffectVid) -> ty::Const<'tcx> { match self.probe_effect_var(vid) { Some(ct) => ct, None => { - ty::Const::new_infer(self.tcx, InferConst::EffectVar(self.root_effect_var(vid)), ty) + ty::Const::new_infer(self.tcx, InferConst::EffectVar(self.root_effect_var(vid))) } } } @@ -424,8 +421,8 @@ pub enum ValuePairs<'tcx> { impl<'tcx> ValuePairs<'tcx> { pub fn ty(&self) -> Option<(Ty<'tcx>, Ty<'tcx>)> { if let ValuePairs::Terms(ExpectedFound { expected, found }) = self - && let Some(expected) = expected.ty() - && let Some(found) = found.ty() + && let Some(expected) = expected.as_type() + && let Some(found) = found.as_type() { Some((expected, found)) } else { @@ -587,6 +584,7 @@ pub enum FixupError { UnresolvedFloatTy(FloatVid), UnresolvedTy(TyVid), UnresolvedConst(ConstVid), + UnresolvedEffect(EffectVid), } /// See the `region_obligations` field for more information. @@ -614,6 +612,7 @@ impl fmt::Display for FixupError { ), UnresolvedTy(_) => write!(f, "unconstrained type"), UnresolvedConst(_) => write!(f, "unconstrained const value"), + UnresolvedEffect(_) => write!(f, "unconstrained effect value"), } } } @@ -737,10 +736,10 @@ impl<'tcx> InferCtxtBuilder<'tcx> { impl<'tcx, T> InferOk<'tcx, T> { /// Extracts `value`, registering any obligations into `fulfill_cx`. - pub fn into_value_registering_obligations( + pub fn into_value_registering_obligations<E: 'tcx>( self, infcx: &InferCtxt<'tcx>, - fulfill_cx: &mut dyn TraitEngine<'tcx>, + fulfill_cx: &mut dyn TraitEngine<'tcx, E>, ) -> T { let InferOk { value, obligations } = self; fulfill_cx.register_predicate_obligations(infcx, obligations); @@ -811,13 +810,13 @@ impl<'tcx> InferCtxt<'tcx> { vars.extend( (0..inner.int_unification_table().len()) .map(|i| ty::IntVid::from_u32(i as u32)) - .filter(|&vid| inner.int_unification_table().probe_value(vid).is_none()) + .filter(|&vid| inner.int_unification_table().probe_value(vid).is_unknown()) .map(|v| Ty::new_int_var(self.tcx, v)), ); vars.extend( (0..inner.float_unification_table().len()) .map(|i| ty::FloatVid::from_u32(i as u32)) - .filter(|&vid| inner.float_unification_table().probe_value(vid).is_none()) + .filter(|&vid| inner.float_unification_table().probe_value(vid).is_unknown()) .map(|v| Ty::new_float_var(self.tcx, v)), ); vars @@ -830,9 +829,7 @@ impl<'tcx> InferCtxt<'tcx> { (0..table.len()) .map(|i| ty::EffectVid::from_usize(i)) .filter(|&vid| table.probe_value(vid).is_unknown()) - .map(|v| { - ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v), self.tcx.types.bool) - }) + .map(|v| ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(v))) .collect() } @@ -991,27 +988,22 @@ impl<'tcx> InferCtxt<'tcx> { Ty::new_var(self.tcx, vid) } - 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(&self, span: Span) -> ty::Const<'tcx> { + self.next_const_var_with_origin(ConstVariableOrigin { span, param_def_id: None }) } - pub fn next_const_var_with_origin( - &self, - ty: Ty<'tcx>, - origin: ConstVariableOrigin, - ) -> ty::Const<'tcx> { + pub fn next_const_var_with_origin(&self, origin: ConstVariableOrigin) -> ty::Const<'tcx> { let vid = self .inner .borrow_mut() .const_unification_table() .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) .vid; - ty::Const::new_var(self.tcx, vid, ty) + ty::Const::new_var(self.tcx, vid) } pub fn next_const_var_in_universe( &self, - ty: Ty<'tcx>, span: Span, universe: ty::UniverseIndex, ) -> ty::Const<'tcx> { @@ -1022,17 +1014,31 @@ impl<'tcx> InferCtxt<'tcx> { .const_unification_table() .new_key(ConstVariableValue::Unknown { origin, universe }) .vid; - ty::Const::new_var(self.tcx, vid, ty) + ty::Const::new_var(self.tcx, vid) + } + + pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid { + 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(ty::IntVarValue::Unknown) } pub fn next_int_var(&self) -> Ty<'tcx> { - let vid = self.inner.borrow_mut().int_unification_table().new_key(None); - Ty::new_int_var(self.tcx, vid) + 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(ty::FloatVarValue::Unknown) } pub fn next_float_var(&self) -> Ty<'tcx> { - let vid = self.inner.borrow_mut().float_unification_table().new_key(None); - Ty::new_float_var(self.tcx, vid) + Ty::new_float_var(self.tcx, self.next_float_var_id()) } /// Creates a fresh region variable with the next available index. @@ -1119,15 +1125,7 @@ impl<'tcx> InferCtxt<'tcx> { .const_unification_table() .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() }) .vid; - ty::Const::new_var( - self.tcx, - const_var_id, - self.tcx - .type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), - ) - .into() + ty::Const::new_var(self.tcx, const_var_id).into() } } } @@ -1141,7 +1139,7 @@ impl<'tcx> InferCtxt<'tcx> { .no_bound_vars() .expect("const parameter types cannot be generic"); debug_assert_eq!(self.tcx.types.bool, ty); - ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid), ty).into() + ty::Const::new_infer(self.tcx, ty::InferConst::EffectVar(effect_vid)).into() } /// Given a set of generics defined on a type or impl, returns the generic parameters mapping each @@ -1234,45 +1232,44 @@ impl<'tcx> InferCtxt<'tcx> { } pub fn shallow_resolve(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Infer(v) = ty.kind() { self.fold_infer_ty(*v).unwrap_or(ty) } else { ty } - } - - // This is separate from `shallow_resolve` to keep that method small and inlinable. - #[inline(never)] - fn fold_infer_ty(&self, v: InferTy) -> Option<Ty<'tcx>> { - match v { - ty::TyVar(v) => { - // Not entirely obvious: if `typ` is a type variable, - // it can be resolved to an int/float variable, which - // can then be recursively resolved, hence the - // recursion. Note though that we prevent type - // variables from unifying to other type variables - // directly (though they may be embedded - // structurally), and we prevent cycles in any case, - // so this recursion should always be of very limited - // depth. - // - // Note: if these two lines are combined into one we get - // dynamic borrow errors on `self.inner`. - let known = self.inner.borrow_mut().type_variables().probe(v).known(); - known.map(|t| self.shallow_resolve(t)) - } + if let ty::Infer(v) = *ty.kind() { + match v { + ty::TyVar(v) => { + // Not entirely obvious: if `typ` is a type variable, + // it can be resolved to an int/float variable, which + // can then be recursively resolved, hence the + // recursion. Note though that we prevent type + // variables from unifying to other type variables + // directly (though they may be embedded + // structurally), and we prevent cycles in any case, + // so this recursion should always be of very limited + // depth. + // + // Note: if these two lines are combined into one we get + // dynamic borrow errors on `self.inner`. + let known = self.inner.borrow_mut().type_variables().probe(v).known(); + known.map_or(ty, |t| self.shallow_resolve(t)) + } + + ty::IntVar(v) => { + match self.inner.borrow_mut().int_unification_table().probe_value(v) { + ty::IntVarValue::IntType(ty) => Ty::new_int(self.tcx, ty), + ty::IntVarValue::UintType(ty) => Ty::new_uint(self.tcx, ty), + ty::IntVarValue::Unknown => ty, + } + } + + ty::FloatVar(v) => { + match self.inner.borrow_mut().float_unification_table().probe_value(v) { + ty::FloatVarValue::Known(ty) => Ty::new_float(self.tcx, ty), + ty::FloatVarValue::Unknown => ty, + } + } - ty::IntVar(v) => self - .inner - .borrow_mut() - .int_unification_table() - .probe_value(v) - .map(|v| v.to_type(self.tcx)), - - ty::FloatVar(v) => self - .inner - .borrow_mut() - .float_unification_table() - .probe_value(v) - .map(|v| v.to_type(self.tcx)), - - ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => None, + ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => ty, + } + } else { + ty } } @@ -1299,7 +1296,7 @@ impl<'tcx> InferCtxt<'tcx> { | ty::ConstKind::Bound(_, _) | ty::ConstKind::Placeholder(_) | ty::ConstKind::Unevaluated(_) - | ty::ConstKind::Value(_) + | ty::ConstKind::Value(_, _) | ty::ConstKind::Error(_) | ty::ConstKind::Expr(_) => ct, } @@ -1321,10 +1318,13 @@ impl<'tcx> InferCtxt<'tcx> { /// or else the root int var in the unification table. pub fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> Ty<'tcx> { let mut inner = self.inner.borrow_mut(); - if let Some(value) = inner.int_unification_table().probe_value(vid) { - value.to_type(self.tcx) - } else { - Ty::new_int_var(self.tcx, inner.int_unification_table().find(vid)) + let value = inner.int_unification_table().probe_value(vid); + match value { + ty::IntVarValue::IntType(ty) => Ty::new_int(self.tcx, ty), + ty::IntVarValue::UintType(ty) => Ty::new_uint(self.tcx, ty), + ty::IntVarValue::Unknown => { + Ty::new_int_var(self.tcx, inner.int_unification_table().find(vid)) + } } } @@ -1332,10 +1332,12 @@ impl<'tcx> InferCtxt<'tcx> { /// or else the root float var in the unification table. pub fn opportunistic_resolve_float_var(&self, vid: ty::FloatVid) -> Ty<'tcx> { let mut inner = self.inner.borrow_mut(); - if let Some(value) = inner.float_unification_table().probe_value(vid) { - value.to_type(self.tcx) - } else { - Ty::new_float_var(self.tcx, inner.float_unification_table().find(vid)) + let value = inner.float_unification_table().probe_value(vid); + match value { + ty::FloatVarValue::Known(ty) => Ty::new_float(self.tcx, ty), + ty::FloatVarValue::Unknown => { + Ty::new_float_var(self.tcx, inner.float_unification_table().find(vid)) + } } } @@ -1449,10 +1451,10 @@ impl<'tcx> InferCtxt<'tcx> { .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> { + fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> { self.map .entry(bv) - .or_insert_with(|| self.infcx.next_const_var(ty, self.span).into()) + .or_insert_with(|| self.infcx.next_const_var(self.span).into()) .expect_const() } } @@ -1506,11 +1508,14 @@ impl<'tcx> InferCtxt<'tcx> { &self, param_env: ty::ParamEnv<'tcx>, unevaluated: ty::UnevaluatedConst<'tcx>, - ty: Ty<'tcx>, span: Span, ) -> Result<ty::Const<'tcx>, ErrorHandled> { match self.const_eval_resolve(param_env, unevaluated, span) { - Ok(Some(val)) => Ok(ty::Const::new_value(self.tcx, val, ty)), + Ok(Some(val)) => Ok(ty::Const::new_value( + self.tcx, + val, + self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args), + )), Ok(None) => { let tcx = self.tcx; let def_id = unevaluated.def; @@ -1626,7 +1631,7 @@ impl<'tcx> InferCtxt<'tcx> { // If `inlined_probe_value` returns a value it's always a // `ty::Int(_)` or `ty::UInt(_)`, which never matches a // `ty::Infer(_)`. - self.inner.borrow_mut().int_unification_table().inlined_probe_value(v).is_some() + self.inner.borrow_mut().int_unification_table().inlined_probe_value(v).is_known() } TyOrConstInferVar::TyFloat(v) => { @@ -1634,7 +1639,7 @@ impl<'tcx> InferCtxt<'tcx> { // `ty::Float(_)`, which never matches a `ty::Infer(_)`. // // Not `inlined_probe_value(v)` because this call site is colder. - self.inner.borrow_mut().float_unification_table().probe_value(v).is_some() + self.inner.borrow_mut().float_unification_table().probe_value(v).is_known() } TyOrConstInferVar::Const(v) => { @@ -1944,11 +1949,6 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { if let ty::ConstKind::Infer(_) = c.kind() { - let ty = c.ty(); - // If the type references param or infer then ICE ICE ICE - if ty.has_non_region_param() || ty.has_non_region_infer() { - bug!("const `{c}`'s type should not reference params or types"); - } ty::Const::new_placeholder( self.tcx, ty::PlaceholderConst { @@ -1959,7 +1959,6 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( idx }), }, - ty, ) } else { c.super_fold_with(self) diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 29c11d4247d..978b92fd898 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -1,15 +1,12 @@ use std::collections::hash_map::Entry; use rustc_data_structures::fx::FxHashMap; +use rustc_middle::ty::error::TypeError; use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{ - self, - error::TypeError, - relate::{self, Relate, RelateResult, TypeRelation}, - Ty, TyCtxt, -}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use crate::infer::region_constraints::VerifyIfEq; +use crate::infer::relate::{self as relate, Relate, RelateResult, TypeRelation}; /// Given a "verify-if-eq" type test like: /// @@ -135,7 +132,7 @@ impl<'tcx> MatchAgainstHigherRankedOutlives<'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> { +impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstHigherRankedOutlives<'tcx> { fn tag(&self) -> &'static str { "MatchAgainstHigherRankedOutlives" } @@ -145,10 +142,10 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> { } #[instrument(level = "trace", skip(self))] - fn relate_with_variance<T: Relate<'tcx>>( + fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>( &mut self, variance: ty::Variance, - _: ty::VarianceDiagInfo<'tcx>, + _: ty::VarianceDiagInfo<TyCtxt<'tcx>>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -208,7 +205,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstHigherRankedOutlives<'tcx> { value: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate<TyCtxt<'tcx>>, { self.pattern_depth.shift_in(1); let result = Ok(pattern.rebind(self.relate(pattern.skip_binder(), value.skip_binder())?)); diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 255ca52d3e9..5b159d62731 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -1,11 +1,11 @@ use super::*; +use crate::infer::relate::RelateResult; use crate::infer::snapshot::CombinedSnapshot; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::graph::{scc::Sccs, vec_graph::VecGraph}; use rustc_index::Idx; use rustc_middle::span_bug; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::relate::RelateResult; impl<'tcx> RegionConstraintCollector<'_, 'tcx> { /// Searches new universes created during `snapshot`, looking for @@ -276,7 +276,7 @@ impl<'a, 'b, 'tcx> LeakCheck<'a, 'b, 'tcx> { other_region: ty::Region<'tcx>, ) -> TypeError<'tcx> { debug!("error: placeholder={:?}, other_region={:?}", placeholder, other_region); - TypeError::RegionsInsufficientlyPolymorphic(placeholder.bound.kind, other_region) + TypeError::RegionsInsufficientlyPolymorphic(placeholder.bound, other_region) } } diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_infer/src/infer/relate/_match.rs index f30270abd5c..30a066a265a 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_infer/src/infer/relate/_match.rs @@ -1,8 +1,10 @@ -use crate::ty::error::TypeError; -use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use crate::ty::{self, InferConst, Ty, TyCtxt}; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; use tracing::{debug, instrument}; +use super::{structurally_relate_tys, Relate, RelateResult, TypeRelation}; +use crate::infer::relate; + /// A type "A" *matches* "B" if the fresh types in B could be /// instantiated with values so as to make it equal to A. Matching is /// intended to be used only on freshened types, and it basically @@ -29,7 +31,7 @@ impl<'tcx> MatchAgainstFreshVars<'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> { +impl<'tcx> TypeRelation<TyCtxt<'tcx>> for MatchAgainstFreshVars<'tcx> { fn tag(&self) -> &'static str { "MatchAgainstFreshVars" } @@ -38,10 +40,10 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> { self.tcx } - fn relate_with_variance<T: Relate<'tcx>>( + fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>( &mut self, _: ty::Variance, - _: ty::VarianceDiagInfo<'tcx>, + _: ty::VarianceDiagInfo<TyCtxt<'tcx>>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -72,12 +74,12 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> { ) => Ok(a), (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { - Err(TypeError::Sorts(relate::expected_found(a, b))) + Err(TypeError::Sorts(ExpectedFound::new(true, a, b))) } (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(self.tcx(), guar)), - _ => relate::structurally_relate_tys(self, a, b), + _ => structurally_relate_tys(self, a, b), } } @@ -97,7 +99,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> { } (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { - return Err(TypeError::ConstMismatch(relate::expected_found(a, b))); + return Err(TypeError::ConstMismatch(ExpectedFound::new(true, a, b))); } _ => {} @@ -112,7 +114,7 @@ impl<'tcx> TypeRelation<'tcx> for MatchAgainstFreshVars<'tcx> { b: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate<TyCtxt<'tcx>>, { Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) } diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index 04ca043e6fe..30cb2bab900 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -22,12 +22,13 @@ use super::glb::Glb; use super::lub::Lub; use super::type_relating::TypeRelating; use super::StructurallyRelateAliases; +use super::{RelateResult, TypeRelation}; +use crate::infer::relate; use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace}; use crate::traits::{Obligation, PredicateObligations}; use rustc_middle::bug; use rustc_middle::infer::unify_key::EffectVarValue; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::relate::{RelateResult, TypeRelation}; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast}; use rustc_middle::ty::{IntType, UintType}; use rustc_span::Span; @@ -68,40 +69,38 @@ impl<'tcx> InferCtxt<'tcx> { match (a.kind(), b.kind()) { // Relate integral variables to other types (&ty::Infer(ty::IntVar(a_id)), &ty::Infer(ty::IntVar(b_id))) => { - self.inner - .borrow_mut() - .int_unification_table() - .unify_var_var(a_id, b_id) - .map_err(|e| int_unification_error(true, e))?; + self.inner.borrow_mut().int_unification_table().union(a_id, b_id); Ok(a) } (&ty::Infer(ty::IntVar(v_id)), &ty::Int(v)) => { - self.unify_integral_variable(true, v_id, IntType(v)) + self.unify_integral_variable(v_id, IntType(v)); + Ok(b) } (&ty::Int(v), &ty::Infer(ty::IntVar(v_id))) => { - self.unify_integral_variable(false, v_id, IntType(v)) + self.unify_integral_variable(v_id, IntType(v)); + Ok(a) } (&ty::Infer(ty::IntVar(v_id)), &ty::Uint(v)) => { - self.unify_integral_variable(true, v_id, UintType(v)) + self.unify_integral_variable(v_id, UintType(v)); + Ok(b) } (&ty::Uint(v), &ty::Infer(ty::IntVar(v_id))) => { - self.unify_integral_variable(false, v_id, UintType(v)) + self.unify_integral_variable(v_id, UintType(v)); + Ok(a) } // Relate floating-point variables to other types (&ty::Infer(ty::FloatVar(a_id)), &ty::Infer(ty::FloatVar(b_id))) => { - self.inner - .borrow_mut() - .float_unification_table() - .unify_var_var(a_id, b_id) - .map_err(|e| float_unification_error(true, e))?; + self.inner.borrow_mut().float_unification_table().union(a_id, b_id); Ok(a) } (&ty::Infer(ty::FloatVar(v_id)), &ty::Float(v)) => { - self.unify_float_variable(true, v_id, v) + self.unify_float_variable(v_id, ty::FloatVarValue::Known(v)); + Ok(b) } (&ty::Float(v), &ty::Infer(ty::FloatVar(v_id))) => { - self.unify_float_variable(false, v_id, v) + self.unify_float_variable(v_id, ty::FloatVarValue::Known(v)); + Ok(a) } // We don't expect `TyVar` or `Fresh*` vars at this point with lazy norm. @@ -123,7 +122,7 @@ impl<'tcx> InferCtxt<'tcx> { (_, ty::Alias(..)) | (ty::Alias(..), _) if self.next_trait_solver() => { match relation.structurally_relate_aliases() { StructurallyRelateAliases::Yes => { - ty::relate::structurally_relate_tys(relation, a, b) + relate::structurally_relate_tys(relation, a, b) } StructurallyRelateAliases::No => { relation.register_type_relate_obligation(a, b); @@ -134,7 +133,7 @@ impl<'tcx> InferCtxt<'tcx> { // All other cases of inference are errors (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { - Err(TypeError::Sorts(ty::relate::expected_found(a, b))) + Err(TypeError::Sorts(ExpectedFound::new(true, a, b))) } // During coherence, opaque types should be treated as *possibly* @@ -146,7 +145,7 @@ impl<'tcx> InferCtxt<'tcx> { Ok(a) } - _ => ty::relate::structurally_relate_tys(relation, a, b), + _ => relate::structurally_relate_tys(relation, a, b), } } @@ -236,43 +235,22 @@ impl<'tcx> InferCtxt<'tcx> { Ok(b) } StructurallyRelateAliases::Yes => { - ty::relate::structurally_relate_consts(relation, a, b) + relate::structurally_relate_consts(relation, a, b) } } } - _ => ty::relate::structurally_relate_consts(relation, a, b), + _ => relate::structurally_relate_consts(relation, a, b), } } - fn unify_integral_variable( - &self, - vid_is_expected: bool, - vid: ty::IntVid, - val: ty::IntVarValue, - ) -> RelateResult<'tcx, Ty<'tcx>> { - self.inner - .borrow_mut() - .int_unification_table() - .unify_var_value(vid, Some(val)) - .map_err(|e| int_unification_error(vid_is_expected, e))?; - match val { - IntType(v) => Ok(Ty::new_int(self.tcx, v)), - UintType(v) => Ok(Ty::new_uint(self.tcx, v)), - } + #[inline(always)] + fn unify_integral_variable(&self, vid: ty::IntVid, val: ty::IntVarValue) { + self.inner.borrow_mut().int_unification_table().union_value(vid, val); } - fn unify_float_variable( - &self, - vid_is_expected: bool, - vid: ty::FloatVid, - val: ty::FloatTy, - ) -> RelateResult<'tcx, Ty<'tcx>> { - self.inner - .borrow_mut() - .float_unification_table() - .unify_var_value(vid, Some(ty::FloatVarValue(val))) - .map_err(|e| float_unification_error(vid_is_expected, e))?; - Ok(Ty::new_float(self.tcx, val)) + #[inline(always)] + fn unify_float_variable(&self, vid: ty::FloatVid, val: ty::FloatVarValue) { + self.inner.borrow_mut().float_unification_table().union_value(vid, val); } fn unify_effect_variable(&self, vid: ty::EffectVid, val: ty::Const<'tcx>) -> ty::Const<'tcx> { @@ -326,7 +304,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { } } -pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> { +pub trait ObligationEmittingRelation<'tcx>: TypeRelation<TyCtxt<'tcx>> { fn span(&self) -> Span; fn param_env(&self) -> ty::ParamEnv<'tcx>; @@ -350,19 +328,3 @@ pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> { /// Register `AliasRelate` obligation(s) that both types must be related to each other. fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>); } - -fn int_unification_error<'tcx>( - a_is_expected: bool, - v: (ty::IntVarValue, ty::IntVarValue), -) -> TypeError<'tcx> { - let (a, b) = v; - TypeError::IntMismatch(ExpectedFound::new(a_is_expected, a, b)) -} - -fn float_unification_error<'tcx>( - a_is_expected: bool, - v: (ty::FloatVarValue, ty::FloatVarValue), -) -> TypeError<'tcx> { - let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v; - TypeError::FloatMismatch(ExpectedFound::new(a_is_expected, a, b)) -} diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index d4c7d752c95..5478afda455 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -1,15 +1,16 @@ use std::mem; use super::StructurallyRelateAliases; +use super::{ObligationEmittingRelation, Relate, RelateResult, TypeRelation}; +use crate::infer::relate; use crate::infer::type_variable::TypeVariableValue; -use crate::infer::{InferCtxt, ObligationEmittingRelation, RegionVariableOrigin}; +use crate::infer::{InferCtxt, RegionVariableOrigin}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::MaxUniverse; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{AliasRelationDirection, InferConst, Term, TypeVisitable, TypeVisitableExt}; @@ -228,7 +229,7 @@ impl<'tcx> InferCtxt<'tcx> { /// Attempts to generalize `source_term` for the type variable `target_vid`. /// This checks for cycles -- that is, whether `source_term` references `target_vid`. - fn generalize<T: Into<Term<'tcx>> + Relate<'tcx>>( + fn generalize<T: Into<Term<'tcx>> + Relate<TyCtxt<'tcx>>>( &self, span: Span, structurally_relate_aliases: StructurallyRelateAliases, @@ -329,6 +330,14 @@ impl<'tcx> Generalizer<'_, 'tcx> { } } + /// Create a new type variable in the universe of the target when + /// generalizing an alias. This has to set `has_unconstrained_ty_var` + /// if we're currently in a bivariant context. + fn next_ty_var_for_alias(&mut self) -> Ty<'tcx> { + self.has_unconstrained_ty_var |= self.ambient_variance == ty::Bivariant; + self.infcx.next_ty_var_in_universe(self.span, self.for_universe) + } + /// An occurs check failure inside of an alias does not mean /// that the types definitely don't unify. We may be able /// to normalize the alias after all. @@ -358,7 +367,7 @@ impl<'tcx> Generalizer<'_, 'tcx> { // // 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)); + return Ok(self.next_ty_var_for_alias()); } let is_nested_alias = mem::replace(&mut self.in_alias, true); @@ -378,7 +387,7 @@ impl<'tcx> Generalizer<'_, 'tcx> { } debug!("generalization failure in alias"); - Ok(self.infcx.next_ty_var_in_universe(self.span, self.for_universe)) + Ok(self.next_ty_var_for_alias()) } } }; @@ -387,7 +396,7 @@ impl<'tcx> Generalizer<'_, 'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { +impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Generalizer<'_, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.infcx.tcx } @@ -422,10 +431,10 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } #[instrument(level = "debug", skip(self, variance, b), ret)] - fn relate_with_variance<T: Relate<'tcx>>( + fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>( &mut self, variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, + _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -645,7 +654,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { { variable_table.union(vid, new_var_id); } - Ok(ty::Const::new_var(self.tcx(), new_var_id, c.ty())) + Ok(ty::Const::new_var(self.tcx(), new_var_id)) } } } @@ -663,11 +672,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { args, args, )?; - Ok(ty::Const::new_unevaluated( - self.tcx(), - ty::UnevaluatedConst { def, args }, - c.ty(), - )) + Ok(ty::Const::new_unevaluated(self.tcx(), ty::UnevaluatedConst { def, args })) } ty::ConstKind::Placeholder(placeholder) => { if self.for_universe.can_name(placeholder.universe) { @@ -691,7 +696,7 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { _: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate<TyCtxt<'tcx>>, { let result = self.relate(a.skip_binder(), a.skip_binder())?; Ok(a.rebind(result)) diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs index a224a86492a..98e8f07c7a2 100644 --- a/compiler/rustc_infer/src/infer/relate/glb.rs +++ b/compiler/rustc_infer/src/infer/relate/glb.rs @@ -1,6 +1,6 @@ //! Greatest lower bound. See [`lattice`]. -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; +use super::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::Span; @@ -21,7 +21,7 @@ impl<'combine, 'infcx, 'tcx> Glb<'combine, 'infcx, 'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { +impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Glb<'_, '_, 'tcx> { fn tag(&self) -> &'static str { "Glb" } @@ -30,10 +30,10 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { self.fields.tcx() } - fn relate_with_variance<T: Relate<'tcx>>( + fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>( &mut self, variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, + _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -81,7 +81,7 @@ impl<'tcx> TypeRelation<'tcx> for Glb<'_, '_, 'tcx> { b: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate<TyCtxt<'tcx>>, { // GLB of a binder and itself is just itself if a == b { diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs index 70ed7cf9af1..cfce28aca5d 100644 --- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs +++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs @@ -1,10 +1,10 @@ //! Helper routines for higher-ranked things. See the `doc` module at //! the end of the file for details. +use super::RelateResult; use crate::infer::snapshot::CombinedSnapshot; use crate::infer::InferCtxt; use rustc_middle::ty::fold::FnMutDelegate; -use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; impl<'tcx> InferCtxt<'tcx> { @@ -43,11 +43,10 @@ impl<'tcx> InferCtxt<'tcx> { ty::PlaceholderType { universe: next_universe, bound: bound_ty }, ) }, - consts: &mut |bound_var: ty::BoundVar, ty| { + consts: &mut |bound_var: ty::BoundVar| { ty::Const::new_placeholder( self.tcx, ty::PlaceholderConst { universe: next_universe, bound: bound_var }, - ty, ) }, }; diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs index 38e25b0d9b6..f05b984142a 100644 --- a/compiler/rustc_infer/src/infer/relate/lattice.rs +++ b/compiler/rustc_infer/src/infer/relate/lattice.rs @@ -21,7 +21,7 @@ use super::combine::ObligationEmittingRelation; use crate::infer::{DefineOpaqueTypes, InferCtxt}; use crate::traits::ObligationCause; -use rustc_middle::ty::relate::RelateResult; +use super::RelateResult; use rustc_middle::ty::TyVar; use rustc_middle::ty::{self, Ty}; @@ -64,8 +64,8 @@ where let infcx = this.infcx(); - let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); - let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); + let a = infcx.shallow_resolve(a); + let b = infcx.shallow_resolve(b); match (a.kind(), b.kind()) { // If one side is known to be a variable and one is not, diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs index 83ab7770770..28dbaa94f95 100644 --- a/compiler/rustc_infer/src/infer/relate/lub.rs +++ b/compiler/rustc_infer/src/infer/relate/lub.rs @@ -6,7 +6,7 @@ use super::StructurallyRelateAliases; use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; use crate::traits::{ObligationCause, PredicateObligations}; -use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; +use super::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::Span; @@ -21,7 +21,7 @@ impl<'combine, 'infcx, 'tcx> Lub<'combine, 'infcx, 'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { +impl<'tcx> TypeRelation<TyCtxt<'tcx>> for Lub<'_, '_, 'tcx> { fn tag(&self) -> &'static str { "Lub" } @@ -30,10 +30,10 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { self.fields.tcx() } - fn relate_with_variance<T: Relate<'tcx>>( + fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>( &mut self, variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, + _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -81,7 +81,7 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> { b: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate<TyCtxt<'tcx>>, { // LUB of a binder and itself is just itself if a == b { diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index 86a01130167..627c527cba1 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -1,6 +1,14 @@ //! This module contains the definitions of most `TypeRelation`s in the type system //! (except for some relations used for diagnostics and heuristics in the compiler). +//! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc). +pub use rustc_middle::ty::relate::*; + +pub use self::_match::MatchAgainstFreshVars; +pub use self::combine::CombineFields; +pub use self::combine::ObligationEmittingRelation; + +pub mod _match; pub(super) mod combine; mod generalize; mod glb; @@ -8,15 +16,3 @@ mod higher_ranked; mod lattice; mod lub; mod type_relating; - -/// Whether aliases should be related structurally or not. Used -/// to adjust the behavior of generalization and combine. -/// -/// This should always be `No` unless in a few special-cases when -/// instantiating canonical responses and in the new solver. Each -/// such case should have a comment explaining why it is used. -#[derive(Debug, Copy, Clone)] -pub enum StructurallyRelateAliases { - Yes, - No, -} diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index 21064fff97f..fd0bc9f44f7 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -1,12 +1,11 @@ use super::combine::CombineFields; use crate::infer::BoundRegionConversionTime::HigherRankedType; -use crate::infer::{ - DefineOpaqueTypes, ObligationEmittingRelation, StructurallyRelateAliases, SubregionOrigin, -}; +use crate::infer::{DefineOpaqueTypes, SubregionOrigin}; use crate::traits::{Obligation, PredicateObligations}; -use rustc_middle::ty::relate::{ - relate_args_invariantly, relate_args_with_variances, Relate, RelateResult, TypeRelation, +use super::{ + relate_args_invariantly, relate_args_with_variances, ObligationEmittingRelation, Relate, + RelateResult, StructurallyRelateAliases, TypeRelation, }; use rustc_middle::ty::TyVar; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -29,7 +28,7 @@ impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> { } } -impl<'tcx> TypeRelation<'tcx> for TypeRelating<'_, '_, 'tcx> { +impl<'tcx> TypeRelation<TyCtxt<'tcx>> for TypeRelating<'_, '_, 'tcx> { fn tag(&self) -> &'static str { "TypeRelating" } @@ -56,10 +55,10 @@ impl<'tcx> TypeRelation<'tcx> for TypeRelating<'_, '_, 'tcx> { } } - fn relate_with_variance<T: Relate<'tcx>>( + fn relate_with_variance<T: Relate<TyCtxt<'tcx>>>( &mut self, variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, + _info: ty::VarianceDiagInfo<TyCtxt<'tcx>>, a: T, b: T, ) -> RelateResult<'tcx, T> { @@ -80,8 +79,8 @@ impl<'tcx> TypeRelation<'tcx> for TypeRelating<'_, '_, 'tcx> { } let infcx = self.fields.infcx; - let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); - let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); + let a = infcx.shallow_resolve(a); + let b = infcx.shallow_resolve(b); match (a.kind(), b.kind()) { (&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => { @@ -226,7 +225,7 @@ impl<'tcx> TypeRelation<'tcx> for TypeRelating<'_, '_, 'tcx> { b: ty::Binder<'tcx, T>, ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> where - T: Relate<'tcx>, + T: Relate<TyCtxt<'tcx>>, { if a == b { // Do nothing diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 21ef2e89523..830d79f52b9 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -167,6 +167,9 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> { ty::ConstKind::Infer(InferConst::Fresh(_)) => { bug!("Unexpected const in full const resolver: {:?}", c); } + ty::ConstKind::Infer(InferConst::EffectVar(evid)) => { + return Err(FixupError::UnresolvedEffect(evid)); + } _ => {} } c.try_super_fold_with(self) diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index 4408251c99d..a086c82c92e 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -244,7 +244,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> 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_with_origin(ct.ty(), origin) + self.infcx.next_const_var_with_origin(origin) } else { ct } diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index e27e6a0a4a1..026b2c1b905 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -1,13 +1,38 @@ +use std::fmt::Debug; + use crate::infer::InferCtxt; use crate::traits::Obligation; use rustc_hir::def_id::DefId; -use rustc_macros::extension; use rustc_middle::ty::{self, Ty, Upcast}; -use super::FulfillmentError; use super::{ObligationCause, PredicateObligation}; -pub trait TraitEngine<'tcx>: 'tcx { +/// A trait error with most of its information removed. This is the error +/// returned by an `ObligationCtxt` by default, and suitable if you just +/// want to see if a predicate holds, and don't particularly care about the +/// error itself (except for if it's an ambiguity or true error). +/// +/// use `ObligationCtxt::new_with_diagnostics` to get a `FulfillmentError`. +#[derive(Clone, Debug)] +pub enum ScrubbedTraitError<'tcx> { + /// A real error. This goal definitely does not hold. + TrueError, + /// An ambiguity. This goal may hold if further inference is done. + Ambiguity, + /// An old-solver-style cycle error, which will fatal. + Cycle(Vec<PredicateObligation<'tcx>>), +} + +impl<'tcx> ScrubbedTraitError<'tcx> { + pub fn is_true_error(&self) -> bool { + match self { + ScrubbedTraitError::TrueError => true, + ScrubbedTraitError::Ambiguity | ScrubbedTraitError::Cycle(_) => false, + } + } +} + +pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx { /// Requires that `ty` must implement the trait with `def_id` in /// the given environment. This trait must not have any type /// parameters (except for `Self`). @@ -37,28 +62,10 @@ pub trait TraitEngine<'tcx>: 'tcx { obligation: PredicateObligation<'tcx>, ); - #[must_use] - fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>; - - fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>; - - fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>; - - /// Among all pending obligations, collect those are stalled on a inference variable which has - /// changed since the last call to `select_where_possible`. Those obligations are marked as - /// successful and returned. - fn drain_unstalled_obligations( - &mut self, - infcx: &InferCtxt<'tcx>, - ) -> Vec<PredicateObligation<'tcx>>; -} - -#[extension(pub trait TraitEngineExt<'tcx>)] -impl<'tcx, T: ?Sized + TraitEngine<'tcx>> T { fn register_predicate_obligations( &mut self, infcx: &InferCtxt<'tcx>, - obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>, + obligations: Vec<PredicateObligation<'tcx>>, ) { for obligation in obligations { self.register_predicate_obligation(infcx, obligation); @@ -66,7 +73,12 @@ impl<'tcx, T: ?Sized + TraitEngine<'tcx>> T { } #[must_use] - fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { + fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E>; + + fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E>; + + #[must_use] + fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> { let errors = self.select_where_possible(infcx); if !errors.is_empty() { return errors; @@ -74,4 +86,18 @@ impl<'tcx, T: ?Sized + TraitEngine<'tcx>> T { self.collect_remaining_errors(infcx) } + + fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>; + + /// Among all pending obligations, collect those are stalled on a inference variable which has + /// changed since the last call to `select_where_possible`. Those obligations are marked as + /// successful and returned. + fn drain_unstalled_obligations( + &mut self, + infcx: &InferCtxt<'tcx>, + ) -> Vec<PredicateObligation<'tcx>>; +} + +pub trait FromSolverError<'tcx, E>: Debug + 'tcx { + fn from_solver_error(infcx: &InferCtxt<'tcx>, error: E) -> Self; } diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 0ae4340098b..ca6c6570e07 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -15,15 +15,14 @@ use hir::def_id::LocalDefId; use rustc_hir as hir; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::Certainty; -use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::{self, Const, Ty, TyCtxt, Upcast}; +use rustc_middle::ty::{self, Ty, TyCtxt, Upcast}; use rustc_span::Span; pub use self::ImplSource::*; pub use self::SelectionError::*; use crate::infer::InferCtxt; -pub use self::engine::{TraitEngine, TraitEngineExt}; +pub use self::engine::{FromSolverError, ScrubbedTraitError, TraitEngine}; pub use self::project::MismatchedProjectionTypes; pub(crate) use self::project::UndoLog; pub use self::project::{ @@ -124,32 +123,6 @@ pub type Selection<'tcx> = ImplSource<'tcx, PredicateObligation<'tcx>>; pub type ObligationInspector<'tcx> = fn(&InferCtxt<'tcx>, &PredicateObligation<'tcx>, Result<Certainty, NoSolution>); -pub struct FulfillmentError<'tcx> { - pub obligation: PredicateObligation<'tcx>, - pub code: FulfillmentErrorCode<'tcx>, - /// Diagnostics only: the 'root' obligation which resulted in - /// the failure to process `obligation`. This is the obligation - /// that was initially passed to `register_predicate_obligation` - pub root_obligation: PredicateObligation<'tcx>, -} - -#[derive(Clone)] -pub enum FulfillmentErrorCode<'tcx> { - /// Inherently impossible to fulfill; this trait is implemented if and only - /// if it is already implemented. - Cycle(Vec<PredicateObligation<'tcx>>), - Select(SelectionError<'tcx>), - Project(MismatchedProjectionTypes<'tcx>), - Subtype(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate - ConstEquate(ExpectedFound<Const<'tcx>>, 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 - /// emitting a fatal error instead. - overflow: Option<bool>, - }, -} - impl<'tcx, O> Obligation<'tcx, O> { pub fn new( tcx: TyCtxt<'tcx>, @@ -198,28 +171,6 @@ impl<'tcx, O> Obligation<'tcx, O> { } } -impl<'tcx> FulfillmentError<'tcx> { - pub fn new( - obligation: PredicateObligation<'tcx>, - code: FulfillmentErrorCode<'tcx>, - root_obligation: PredicateObligation<'tcx>, - ) -> FulfillmentError<'tcx> { - FulfillmentError { obligation, code, root_obligation } - } - - pub fn is_true_error(&self) -> bool { - match self.code { - FulfillmentErrorCode::Select(_) - | FulfillmentErrorCode::Project(_) - | FulfillmentErrorCode::Subtype(_, _) - | FulfillmentErrorCode::ConstEquate(_, _) => true, - FulfillmentErrorCode::Cycle(_) | FulfillmentErrorCode::Ambiguity { overflow: _ } => { - false - } - } - } -} - impl<'tcx> PolyTraitObligation<'tcx> { pub fn polarity(&self) -> ty::PredicatePolarity { self.predicate.skip_binder().polarity diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index b616d37e5b5..b26734a296f 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -29,33 +29,6 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> { } } -impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code) - } -} - -impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use traits::FulfillmentErrorCode::*; - match *self { - Select(ref e) => write!(f, "{e:?}"), - Project(ref e) => write!(f, "{e:?}"), - Subtype(ref a, ref b) => { - write!(f, "CodeSubtypeError({a:?}, {b:?})") - } - ConstEquate(ref a, ref b) => { - write!(f, "CodeConstEquateError({a:?}, {b:?})") - } - Ambiguity { overflow: None } => write!(f, "Ambiguity"), - Ambiguity { overflow: Some(suggest_increasing_limit) } => { - write!(f, "Overflow({suggest_increasing_limit})") - } - Cycle(ref cycle) => write!(f, "Cycle({cycle:?})"), - } - } -} - impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "MismatchedProjectionTypes({:?})", self.err) diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 5254a6576f9..c95a10f4e8d 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -14,7 +14,7 @@ use rustc_lint::LintStore; use rustc_middle::ty; use rustc_middle::ty::CurrentGcx; use rustc_middle::util::Providers; -use rustc_parse::maybe_new_parser_from_source_str; +use rustc_parse::new_parser_from_source_str; use rustc_query_impl::QueryCtxt; use rustc_query_system::query::print_query_stack; use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName}; @@ -67,7 +67,7 @@ pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec<String>) -> Cfg { }; } - match maybe_new_parser_from_source_str(&psess, filename, s.to_string()) { + match new_parser_from_source_str(&psess, filename, s.to_string()) { Ok(mut parser) => match parser.parse_meta_item() { Ok(meta_item) if parser.token == token::Eof => { if meta_item.path.segments.len() != 1 { @@ -166,7 +166,7 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec<String>) -> CheckCfg { error!("expected `cfg(name, values(\"value1\", \"value2\", ... \"valueN\"))`") }; - let mut parser = match maybe_new_parser_from_source_str(&psess, filename, s.to_string()) { + let mut parser = match new_parser_from_source_str(&psess, filename, s.to_string()) { Ok(parser) => parser, Err(errs) => { errs.into_iter().for_each(|err| err.cancel()); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 33995f80162..d52286d5887 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -19,7 +19,9 @@ use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt}; use rustc_middle::util::Providers; -use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr}; +use rustc_parse::{ + new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal, validate_attr, +}; use rustc_passes::{abi_test, hir_stats, layout_test}; use rustc_resolve::Resolver; use rustc_session::code_stats::VTableSizeInfo; @@ -42,11 +44,14 @@ use std::{env, fs, iter}; use tracing::{info, instrument}; pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> { - let krate = sess.time("parse_crate", || match &sess.io.input { - Input::File(file) => parse_crate_from_file(file, &sess.psess), - Input::Str { input, name } => { - parse_crate_from_source_str(name.clone(), input.clone(), &sess.psess) - } + let krate = sess.time("parse_crate", || { + let mut parser = unwrap_or_emit_fatal(match &sess.io.input { + Input::File(file) => new_parser_from_file(&sess.psess, file, None), + Input::Str { input, name } => { + new_parser_from_source_str(&sess.psess, name.clone(), input.clone()) + } + }); + parser.parse_crate_mod() })?; if sess.opts.unstable_opts.input_stats { @@ -459,7 +464,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P } } - for &cnum in tcx.crates_including_speculative(()) { + for &cnum in tcx.crates(()) { let source = tcx.used_crate_source(cnum); if let Some((path, _)) = &source.dylib { files.push(escape_dep_filename(&path.display().to_string())); @@ -832,7 +837,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { let traits = tcx.traits(LOCAL_CRATE); for &tr in traits { - if !tcx.check_is_object_safe(tr) { + if !tcx.is_object_safe(tr) { continue; } diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index fb71cb60140..733c73bc3d0 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -445,7 +445,8 @@ lint_macro_is_private = macro `{$ident}` is private lint_macro_rule_never_used = rule #{$n} of macro `{$name}` is never used lint_macro_use_deprecated = - deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead + applying the `#[macro_use]` attribute to an `extern crate` item is deprecated + .help = remove it and import macros at use sites with a `use` item instead lint_malformed_attribute = malformed lint attribute input @@ -456,12 +457,15 @@ lint_map_unit_fn = `Iterator::map` call that discard the iterator's values .map_label = after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items .suggestion = you might have meant to use `Iterator::for_each` -lint_metavariable_still_repeating = variable '{$name}' is still repeating at this depth +lint_metavariable_still_repeating = variable `{$name}` is still repeating at this depth lint_metavariable_wrong_operator = meta-variable repeats with different Kleene operator lint_missing_fragment_specifier = missing fragment specifier +lint_missing_unsafe_on_extern = extern blocks should be unsafe + .suggestion = needs `unsafe` before the extern keyword + lint_mixed_script_confusables = the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables .includes_note = the usage includes {$includes} @@ -632,11 +636,8 @@ lint_pattern_in_bodiless = patterns aren't allowed in functions without bodies lint_pattern_in_foreign = patterns aren't allowed in foreign function declarations .label = pattern not allowed in foreign function -lint_private_extern_crate_reexport = - extern crate `{$ident}` is private, and cannot be re-exported, consider declaring with `pub` - -lint_proc_macro_back_compat = using an old version of `{$crate_name}` - .note = older versions of the `{$crate_name}` crate will stop compiling in future versions of Rust; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives +lint_private_extern_crate_reexport = extern crate `{$ident}` is private and cannot be re-exported + .suggestion = consider making the `extern crate` item publicly accessible lint_proc_macro_derive_resolution_fallback = cannot find {$ns} `{$ident}` in this scope .label = names from parent modules are not accessible without an explicit import @@ -847,7 +848,8 @@ lint_unused_coroutine = }{$post} that must be used .note = coroutines are lazy and do nothing unless resumed -lint_unused_crate_dependency = external crate `{$extern_crate}` unused in `{$local_crate}`: remove the dependency or add `use {$extern_crate} as _;` +lint_unused_crate_dependency = extern crate `{$extern_crate}` is unused in crate `{$local_crate}` + .help = remove the dependency or add `use {$extern_crate} as _;` to the crate root lint_unused_def = unused {$pre}`{$def}`{$post} that must be used .suggestion = use `let _ = ...` to ignore the resulting value diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 87c433a5dc0..8c9abeafacf 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -51,7 +51,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_hir::intravisit::FnKind as HirFnKind; -use rustc_hir::{Body, FnDecl, GenericParamKind, Node, PatKind, PredicateOrigin}; +use rustc_hir::{Body, FnDecl, GenericParamKind, PatKind, PredicateOrigin}; use rustc_middle::bug; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::LayoutOf; @@ -1423,11 +1423,20 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub { self.perform_lint(cx, "item", foreign_item.owner_id.def_id, foreign_item.vis_span, true); } - fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) { - if matches!(cx.tcx.parent_hir_node(field.hir_id), Node::Variant(_)) { - return; - } - self.perform_lint(cx, "field", field.def_id, field.vis_span, false); + fn check_field_def(&mut self, _cx: &LateContext<'_>, _field: &hir::FieldDef<'_>) { + // - If an ADT definition is reported then we don't need to check fields + // (as it would add unnecessary complexity to the source code, the struct + // definition is in the immediate proximity to give the "real" visibility). + // - If an ADT is not reported because it's not `pub` - we don't need to + // check fields. + // - If an ADT is not reported because it's reachable - we also don't need + // to check fields because then they are reachable by construction if they + // are pub. + // + // Therefore in no case we check the fields. + // + // cf. https://github.com/rust-lang/rust/pull/126013#issuecomment-2152839205 + // cf. https://github.com/rust-lang/rust/pull/126040#issuecomment-2152944506 } fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) { diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index 26f34486a3d..83640d7210f 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -159,9 +159,6 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & BuiltinLintDiag::LegacyDeriveHelpers(label_span) => { lints::LegacyDeriveHelpers { span: label_span }.decorate_lint(diag); } - BuiltinLintDiag::ProcMacroBackCompat { crate_name, fixed_version } => { - lints::ProcMacroBackCompat { crate_name, fixed_version }.decorate_lint(diag); - } BuiltinLintDiag::OrPatternsBackCompat(suggestion_span, suggestion) => { lints::OrPatternsBackCompat { span: suggestion_span, suggestion }.decorate_lint(diag); } @@ -205,6 +202,9 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & }; lints::DeprecatedWhereClauseLocation { suggestion }.decorate_lint(diag); } + BuiltinLintDiag::MissingUnsafeOnExtern { suggestion } => { + lints::MissingUnsafeOnExtern { suggestion }.decorate_lint(diag); + } BuiltinLintDiag::SingleUseLifetime { param_span, use_span: Some((use_span, elide)), @@ -340,8 +340,9 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & lints::MacroUseDeprecated.decorate_lint(diag); } BuiltinLintDiag::UnusedMacroUse => lints::UnusedMacroUse.decorate_lint(diag), - BuiltinLintDiag::PrivateExternCrateReexport(ident) => { - lints::PrivateExternCrateReexport { ident }.decorate_lint(diag); + BuiltinLintDiag::PrivateExternCrateReexport { source: ident, extern_crate_span } => { + lints::PrivateExternCrateReexport { ident, sugg: extern_crate_span.shrink_to_lo() } + .decorate_lint(diag); } BuiltinLintDiag::UnusedLabel => lints::UnusedLabel.decorate_lint(diag), BuiltinLintDiag::MacroIsPrivate(ident) => { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 84d46ef3b65..b377da31a58 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2313,6 +2313,7 @@ pub mod unexpected_cfg_value { #[derive(LintDiagnostic)] #[diag(lint_macro_use_deprecated)] +#[help] pub struct MacroUseDeprecated; #[derive(LintDiagnostic)] @@ -2323,6 +2324,8 @@ pub struct UnusedMacroUse; #[diag(lint_private_extern_crate_reexport, code = E0365)] pub struct PrivateExternCrateReexport { pub ident: Ident, + #[suggestion(code = "pub ", style = "verbose", applicability = "maybe-incorrect")] + pub sugg: Span, } #[derive(LintDiagnostic)] @@ -2416,6 +2419,7 @@ pub struct UnknownMacroVariable { #[derive(LintDiagnostic)] #[diag(lint_unused_crate_dependency)] +#[help] pub struct UnusedCrateDependency { pub extern_crate: Symbol, pub local_crate: Symbol, @@ -2650,14 +2654,6 @@ pub struct LegacyDeriveHelpers { } #[derive(LintDiagnostic)] -#[diag(lint_proc_macro_back_compat)] -#[note] -pub struct ProcMacroBackCompat { - pub crate_name: String, - pub fixed_version: String, -} - -#[derive(LintDiagnostic)] #[diag(lint_or_patterns_back_compat)] pub struct OrPatternsBackCompat { #[suggestion(code = "{suggestion}", applicability = "machine-applicable")] @@ -2739,6 +2735,13 @@ pub enum DeprecatedWhereClauseLocationSugg { } #[derive(LintDiagnostic)] +#[diag(lint_missing_unsafe_on_extern)] +pub struct MissingUnsafeOnExtern { + #[suggestion(code = "unsafe ", applicability = "machine-applicable")] + pub suggestion: Span, +} + +#[derive(LintDiagnostic)] #[diag(lint_single_use_lifetime)] pub struct SingleUseLifetime { #[label(lint_label_param)] diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index 48d140c6b7f..aa1d94228ea 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -38,10 +38,10 @@ declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTAB impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { let def_id = item.owner_id.to_def_id(); - // NOTE(nbdd0121): use `object_safety_violations` instead of `check_is_object_safe` because + // NOTE(nbdd0121): use `object_safety_violations` instead of `is_object_safe` because // the latter will report `where_clause_object_safety` lint. if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind - && cx.tcx.object_safety_violations(def_id).is_empty() + && cx.tcx.is_object_safe(def_id) { let direct_super_traits_iter = cx .tcx diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index eda40e4a011..6098da990c0 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -83,7 +83,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound { }; // Only check types, since those are the only things that may // have opaques in them anyways. - let Some(proj_term) = proj.term.ty() else { return }; + let Some(proj_term) = proj.term.as_type() else { return }; // HACK: `impl Trait<Assoc = impl Trait2>` from an RPIT is "ok"... if let ty::Alias(ty::Opaque, opaque_ty) = *proj_term.kind() diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 9d3a838666a..f3a904022e9 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1741,13 +1741,13 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations { let abi = cx.tcx.hir().get_foreign_abi(it.hir_id()); match it.kind { - hir::ForeignItemKind::Fn(decl, _, _) if !vis.is_internal_abi(abi) => { + hir::ForeignItemKind::Fn(decl, _, _, _) if !vis.is_internal_abi(abi) => { vis.check_foreign_fn(it.owner_id.def_id, decl); } - hir::ForeignItemKind::Static(ty, _) if !vis.is_internal_abi(abi) => { + hir::ForeignItemKind::Static(ty, _, _) if !vis.is_internal_abi(abi) => { vis.check_foreign_static(it.owner_id, ty.span); } - hir::ForeignItemKind::Fn(decl, _, _) => vis.check_fn(it.owner_id.def_id, decl), + hir::ForeignItemKind::Fn(decl, _, _, _) => vis.check_fn(it.owner_id.def_id, decl), hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (), } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 93995fe60a3..726bd0de129 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -66,6 +66,7 @@ declare_lint_pass! { META_VARIABLE_MISUSE, MISSING_ABI, MISSING_FRAGMENT_SPECIFIER, + MISSING_UNSAFE_ON_EXTERN, MUST_NOT_SUSPEND, NAMED_ARGUMENTS_USED_POSITIONALLY, NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE, @@ -76,7 +77,6 @@ declare_lint_pass! { PATTERNS_IN_FNS_WITHOUT_BODY, PRIVATE_BOUNDS, PRIVATE_INTERFACES, - PROC_MACRO_BACK_COMPAT, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, PUB_USE_OF_PRIVATE_EXTERN_CRATE, REDUNDANT_LIFETIMES, @@ -136,7 +136,6 @@ declare_lint_pass! { USELESS_DEPRECATED, WARNINGS, WASM_C_ABI, - WHERE_CLAUSES_OBJECT_SAFETY, WRITES_THROUGH_IMMUTABLE_POINTER, // tidy-alphabetical-end ] @@ -512,8 +511,9 @@ declare_lint! { /// This will produce: /// /// ```text - /// error: external crate `regex` unused in `lint_example`: remove the dependency or add `use regex as _;` + /// error: extern crate `regex` is unused in crate `lint_example` /// | + /// = help: remove the dependency or add `use regex as _;` to the crate root /// note: the lint level is defined here /// --> src/lib.rs:1:9 /// | @@ -2094,47 +2094,6 @@ declare_lint! { } declare_lint! { - /// The `where_clauses_object_safety` lint detects for [object safety] of - /// [where clauses]. - /// - /// [object safety]: https://doc.rust-lang.org/reference/items/traits.html#object-safety - /// [where clauses]: https://doc.rust-lang.org/reference/items/generics.html#where-clauses - /// - /// ### Example - /// - /// ```rust,no_run - /// trait Trait {} - /// - /// trait X { fn foo(&self) where Self: Trait; } - /// - /// impl X for () { fn foo(&self) {} } - /// - /// impl Trait for dyn X {} - /// - /// // Segfault at opt-level 0, SIGILL otherwise. - /// pub fn main() { <dyn X as X>::foo(&()); } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// The compiler previously allowed these object-unsafe bounds, which was - /// incorrect. This is a [future-incompatible] lint to transition this to - /// a hard error in the future. See [issue #51443] for more details. - /// - /// [issue #51443]: https://github.com/rust-lang/rust/issues/51443 - /// [future-incompatible]: ../index.md#future-incompatible-lints - pub WHERE_CLAUSES_OBJECT_SAFETY, - Warn, - "checks the object safety of where clauses", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, - reference: "issue #51443 <https://github.com/rust-lang/rust/issues/51443>", - }; -} - -declare_lint! { /// The `proc_macro_derive_resolution_fallback` lint detects proc macro /// derives using inaccessible names from parent modules. /// @@ -2202,8 +2161,7 @@ declare_lint! { } declare_lint! { - /// The `macro_use_extern_crate` lint detects the use of the - /// [`macro_use` attribute]. + /// The `macro_use_extern_crate` lint detects the use of the [`macro_use` attribute]. /// /// ### Example /// @@ -2221,12 +2179,13 @@ declare_lint! { /// This will produce: /// /// ```text - /// error: deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead + /// error: applying the `#[macro_use]` attribute to an `extern crate` item is deprecated /// --> src/main.rs:3:1 /// | /// 3 | #[macro_use] /// | ^^^^^^^^^^^^ /// | + /// = help: remove it and import macros at use sites with a `use` item instead /// note: the lint level is defined here /// --> src/main.rs:1:9 /// | @@ -3707,53 +3666,6 @@ declare_lint! { } declare_lint! { - /// The `proc_macro_back_compat` lint detects uses of old versions of certain - /// proc-macro crates, which have hardcoded workarounds in the compiler. - /// - /// ### Example - /// - /// ```rust,ignore (needs-dependency) - /// - /// use time_macros_impl::impl_macros; - /// struct Foo; - /// impl_macros!(Foo); - /// ``` - /// - /// This will produce: - /// - /// ```text - /// warning: using an old version of `time-macros-impl` - /// ::: $DIR/group-compat-hack.rs:27:5 - /// | - /// LL | impl_macros!(Foo); - /// | ------------------ in this macro invocation - /// | - /// = note: `#[warn(proc_macro_back_compat)]` on by default - /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - /// = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - /// = note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage - /// = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - /// ``` - /// - /// ### Explanation - /// - /// Eventually, the backwards-compatibility hacks present in the compiler will be removed, - /// causing older versions of certain crates to stop compiling. - /// This is a [future-incompatible] lint to ease the transition to an error. - /// See [issue #83125] for more details. - /// - /// [issue #83125]: https://github.com/rust-lang/rust/issues/83125 - /// [future-incompatible]: ../index.md#future-incompatible-lints - pub PROC_MACRO_BACK_COMPAT, - Deny, - "detects usage of old versions of certain proc-macro crates", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #83125 <https://github.com/rust-lang/rust/issues/83125>", - }; -} - -declare_lint! { /// The `rust_2021_incompatible_or_patterns` lint detects usage of old versions of or-patterns. /// /// ### Example @@ -4893,3 +4805,40 @@ declare_lint! { reference: "issue #27970 <https://github.com/rust-lang/rust/issues/27970>", }; } + +declare_lint! { + /// The `missing_unsafe_on_extern` lint detects missing unsafe keyword on extern declarations. + /// + /// ### Example + /// + /// ```rust + /// #![feature(unsafe_extern_blocks)] + /// #![warn(missing_unsafe_on_extern)] + /// #![allow(dead_code)] + /// + /// extern "C" { + /// fn foo(_: i32); + /// } + /// + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Declaring extern items, even without ever using them, can cause Undefined Behavior. We + /// should consider all sources of Undefined Behavior to be unsafe. + /// + /// This is a [future-incompatible] lint to transition this to a + /// hard error in the future. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub MISSING_UNSAFE_ON_EXTERN, + Allow, + "detects missing unsafe keyword on extern declarations", + @future_incompatible = FutureIncompatibleInfo { + reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024), + reference: "issue #123743 <https://github.com/rust-lang/rust/issues/123743>", + }; +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index c8a9fb02bf2..8bf25024afe 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -618,10 +618,6 @@ pub enum BuiltinLintDiag { is_foreign: bool, }, LegacyDeriveHelpers(Span), - ProcMacroBackCompat { - crate_name: String, - fixed_version: String, - }, OrPatternsBackCompat(Span, String), ReservedPrefix(Span, String), TrailingMacro(bool, Ident), @@ -630,6 +626,9 @@ pub enum BuiltinLintDiag { UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), DeprecatedWhereclauseLocation(Span, Option<(Span, String)>), + MissingUnsafeOnExtern { + suggestion: Span, + }, SingleUseLifetime { /// Span of the parameter which declares this lifetime. param_span: Span, @@ -707,7 +706,10 @@ pub enum BuiltinLintDiag { }, MacroUseDeprecated, UnusedMacroUse, - PrivateExternCrateReexport(Ident), + PrivateExternCrateReexport { + source: Ident, + extern_crate_span: Span, + }, UnusedLabel, MacroIsPrivate(Ident), UnusedMacroDefinition(Symbol), diff --git a/compiler/rustc_macros/src/extension.rs b/compiler/rustc_macros/src/extension.rs index 5377bbdfeab..bbaa477237b 100644 --- a/compiler/rustc_macros/src/extension.rs +++ b/compiler/rustc_macros/src/extension.rs @@ -6,6 +6,7 @@ use syn::spanned::Spanned; use syn::{ braced, parse_macro_input, Attribute, Generics, ImplItem, Pat, PatIdent, Path, Signature, Token, TraitItem, TraitItemConst, TraitItemFn, TraitItemMacro, TraitItemType, Type, Visibility, + WhereClause, }; pub(crate) fn extension( @@ -13,7 +14,7 @@ pub(crate) fn extension( input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { let ExtensionAttr { vis, trait_ } = parse_macro_input!(attr as ExtensionAttr); - let Impl { attrs, generics, self_ty, items } = parse_macro_input!(input as Impl); + let Impl { attrs, generics, self_ty, items, wc } = parse_macro_input!(input as Impl); let headers: Vec<_> = items .iter() .map(|item| match item { @@ -59,7 +60,7 @@ pub(crate) fn extension( #(#headers)* } - impl #generics #trait_ for #self_ty { + impl #generics #trait_ for #self_ty #wc { #(#items)* } } @@ -133,6 +134,7 @@ struct Impl { generics: Generics, self_ty: Type, items: Vec<ImplItem>, + wc: Option<WhereClause>, } impl Parse for Impl { @@ -141,6 +143,7 @@ impl Parse for Impl { let _: Token![impl] = input.parse()?; let generics = input.parse()?; let self_ty = input.parse()?; + let wc = input.parse()?; let content; let _brace_token = braced!(content in input); @@ -149,6 +152,6 @@ impl Parse for Impl { items.push(content.parse()?); } - Ok(Impl { attrs, generics, self_ty, items }) + Ok(Impl { attrs, generics, self_ty, items, wc }) } } diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 25675e06e38..ceff1da9763 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -314,6 +314,17 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { let mut query_description_stream = quote! {}; let mut query_cached_stream = quote! {}; let mut feedable_queries = quote! {}; + let mut errors = quote! {}; + + macro_rules! assert { + ( $cond:expr, $span:expr, $( $tt:tt )+ ) => { + if !$cond { + errors.extend( + Error::new($span, format!($($tt)+)).into_compile_error(), + ); + } + } + } for query in queries.0 { let Query { name, arg, modifiers, .. } = &query; @@ -369,10 +380,15 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { [#attribute_stream] fn #name(#arg) #result, }); - if modifiers.feedable.is_some() { - assert!(modifiers.anon.is_none(), "Query {name} cannot be both `feedable` and `anon`."); + if let Some(feedable) = &modifiers.feedable { + assert!( + modifiers.anon.is_none(), + feedable.span(), + "Query {name} cannot be both `feedable` and `anon`." + ); assert!( modifiers.eval_always.is_none(), + feedable.span(), "Query {name} cannot be both `feedable` and `eval_always`." ); feedable_queries.extend(quote! { @@ -407,5 +423,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { use super::*; #query_cached_stream } + #errors }) } diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 44a3e9760e1..ad283117d7e 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -581,7 +581,6 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { self.tcx.crate_types().iter().all(|c| *c == CrateType::Rlib), hash, extra_filename, - false, // is_host path_kind, ); diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index bf9bbfb8cfa..9c69ab2344e 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -144,7 +144,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { && sess.crt_static(Some(ty)) && !sess.target.crt_static_allows_dylibs) { - for &cnum in tcx.used_crates(()).iter() { + for &cnum in tcx.crates(()).iter() { if tcx.dep_kind(cnum).macros_only() { continue; } @@ -165,7 +165,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { // Sweep all crates for found dylibs. Add all dylibs, as well as their // dependencies, ensuring there are no conflicts. The only valid case for a // dependency to be relied upon twice is for both cases to rely on a dylib. - for &cnum in tcx.used_crates(()).iter() { + for &cnum in tcx.crates(()).iter() { if tcx.dep_kind(cnum).macros_only() { continue; } @@ -183,7 +183,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { } // Collect what we've got so far in the return vector. - let last_crate = tcx.used_crates(()).len(); + let last_crate = tcx.crates(()).len(); let mut ret = (1..last_crate + 1) .map(|cnum| match formats.get(&CrateNum::new(cnum)) { Some(&RequireDynamic) => Linkage::Dynamic, @@ -197,7 +197,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { // // If the crate hasn't been included yet and it's not actually required // (e.g., it's an allocator) then we skip it here as well. - for &cnum in tcx.used_crates(()).iter() { + for &cnum in tcx.crates(()).iter() { let src = tcx.used_crate_source(cnum); if src.dylib.is_none() && !formats.contains_key(&cnum) @@ -285,7 +285,7 @@ fn add_library( fn attempt_static(tcx: TyCtxt<'_>, unavailable: &mut Vec<CrateNum>) -> Option<DependencyList> { let all_crates_available_as_rlib = tcx - .used_crates(()) + .crates(()) .iter() .copied() .filter_map(|cnum| { @@ -306,7 +306,7 @@ fn attempt_static(tcx: TyCtxt<'_>, unavailable: &mut Vec<CrateNum>) -> Option<De // All crates are available in an rlib format, so we're just going to link // everything in explicitly so long as it's actually required. let mut ret = tcx - .used_crates(()) + .crates(()) .iter() .map(|&cnum| match tcx.dep_kind(cnum) { CrateDepKind::Explicit => Linkage::Static, diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 73443de3553..90fe52a3438 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -222,7 +222,6 @@ use rustc_data_structures::owned_slice::slice_owned; use rustc_data_structures::svh::Svh; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_fs_util::try_canonicalize; -use rustc_session::config; use rustc_session::cstore::CrateSource; use rustc_session::filesearch::FileSearch; use rustc_session::search_paths::PathKind; @@ -309,7 +308,6 @@ impl<'a> CrateLocator<'a> { is_rlib: bool, hash: Option<Svh>, extra_filename: Option<&'a str>, - is_host: bool, path_kind: PathKind, ) -> CrateLocator<'a> { let needs_object_code = sess.opts.output_types.should_codegen(); @@ -340,17 +338,9 @@ impl<'a> CrateLocator<'a> { }, hash, extra_filename, - target: if is_host { &sess.host } else { &sess.target }, - triple: if is_host { - TargetTriple::from_triple(config::host_triple()) - } else { - sess.opts.target_triple.clone() - }, - filesearch: if is_host { - sess.host_filesearch(path_kind) - } else { - sess.target_filesearch(path_kind) - }, + target: &sess.target, + triple: sess.opts.target_triple.clone(), + filesearch: sess.target_filesearch(path_kind), is_proc_macro: false, crate_rejections: CrateRejections::default(), } @@ -424,12 +414,18 @@ impl<'a> CrateLocator<'a> { debug!("testing {}", spf.path.display()); let f = &spf.file_name_str; - let (hash, kind) = if f.starts_with(rlib_prefix) && f.ends_with(rlib_suffix) { - (&f[rlib_prefix.len()..(f.len() - rlib_suffix.len())], CrateFlavor::Rlib) - } else if f.starts_with(rmeta_prefix) && f.ends_with(rmeta_suffix) { - (&f[rmeta_prefix.len()..(f.len() - rmeta_suffix.len())], CrateFlavor::Rmeta) - } else if f.starts_with(dylib_prefix) && f.ends_with(dylib_suffix.as_ref()) { - (&f[dylib_prefix.len()..(f.len() - dylib_suffix.len())], CrateFlavor::Dylib) + let (hash, kind) = if let Some(f) = f.strip_prefix(rlib_prefix) + && let Some(f) = f.strip_suffix(rlib_suffix) + { + (f, CrateFlavor::Rlib) + } else if let Some(f) = f.strip_prefix(rmeta_prefix) + && let Some(f) = f.strip_suffix(rmeta_suffix) + { + (f, CrateFlavor::Rmeta) + } else if let Some(f) = f.strip_prefix(dylib_prefix) + && let Some(f) = f.strip_suffix(dylib_suffix.as_ref()) + { + (f, CrateFlavor::Dylib) } else { if f.starts_with(staticlib_prefix) && f.ends_with(staticlib_suffix.as_ref()) { self.crate_rejections.via_kind.push(CrateMismatch { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index f6b9c7ed992..1cef35f082b 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -314,6 +314,7 @@ provide! { tcx, def_id, other, cdata, extern_crate => { cdata.extern_crate.map(|c| &*tcx.arena.alloc(c)) } is_no_builtins => { cdata.root.no_builtins } symbol_mangling_version => { cdata.root.symbol_mangling_version } + specialization_enabled_in => { cdata.root.specialization_enabled_in } reachable_non_generics => { let reachable_non_generics = tcx .exported_symbols(cdata.cnum) @@ -439,7 +440,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { // traversal, but not globally minimal across all crates. let bfs_queue = &mut VecDeque::new(); - for &cnum in tcx.crates_including_speculative(()) { + for &cnum in tcx.crates(()) { // Ignore crates without a corresponding local `extern crate` item. if tcx.missing_extern_crate_item(cnum) { continue; @@ -509,7 +510,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { tcx.arena .alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE)) }, - crates_including_speculative: |tcx, ()| { + crates: |tcx, ()| { // The list of loaded crates is now frozen in query cache, // so make sure cstore is not mutably accessed from here on. tcx.untracked().cstore.freeze(); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 4f186981a76..89da0df8575 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -741,6 +741,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { expn_data, expn_hashes, def_path_hash_map, + specialization_enabled_in: tcx.specialization_enabled_in(LOCAL_CRATE), }) }); @@ -1899,7 +1900,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let deps = self .tcx - .crates_including_speculative(()) + .crates(()) .iter() .map(|&cnum| { let dep = CrateDep { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index c2cf5b6b712..87900c23d8d 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -290,6 +290,8 @@ pub(crate) struct CrateRoot { panic_runtime: bool, profiler_runtime: bool, symbol_mangling_version: SymbolManglingVersion, + + specialization_enabled_in: bool, } /// On-disk representation of `DefId`. diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 23a6ceb4d3e..dcbddad2dbc 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -156,10 +156,14 @@ fixed_size_enum! { ( Impl { of_trait: false } ) ( Impl { of_trait: true } ) ( Closure ) - ( Static { mutability: ast::Mutability::Not, nested: false } ) - ( Static { mutability: ast::Mutability::Mut, nested: false } ) - ( Static { mutability: ast::Mutability::Not, nested: true } ) - ( Static { mutability: ast::Mutability::Mut, nested: true } ) + ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Not, nested: false } ) + ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Not, nested: false } ) + ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Mut, nested: false } ) + ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Mut, nested: false } ) + ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Not, nested: true } ) + ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Not, nested: true } ) + ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Mut, nested: true } ) + ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Mut, nested: true } ) ( Ctor(CtorOf::Struct, CtorKind::Fn) ) ( Ctor(CtorOf::Struct, CtorKind::Const) ) ( Ctor(CtorOf::Variant, CtorKind::Fn) ) diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index ab0c598ea0c..3dc592980fd 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -11,7 +11,6 @@ either = "1.5.0" field-offset = "0.3.5" gsgdt = "0.1.2" polonius-engine = "0.13.0" -rustc-rayon = { version = "0.5.0", optional = true } rustc-rayon-core = { version = "0.5.0", optional = true } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } @@ -28,7 +27,6 @@ rustc_hir = { path = "../rustc_hir" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } -rustc_next_trait_solver = { path = "../rustc_next_trait_solver" } rustc_query_system = { path = "../rustc_query_system" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } @@ -42,5 +40,5 @@ tracing = "0.1" [features] # tidy-alphabetical-start -rustc_use_parallel_compiler = ["rustc-rayon", "rustc-rayon-core"] +rustc_use_parallel_compiler = ["rustc-rayon-core"] # tidy-alphabetical-end diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index bf6ab800064..de786c38326 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -62,7 +62,7 @@ macro_rules! arena_types { [] candidate_step: rustc_middle::traits::query::CandidateStep<'tcx>, [] autoderef_bad_ty: rustc_middle::traits::query::MethodAutoderefBadTy<'tcx>, [] canonical_goal_evaluation: - rustc_next_trait_solver::solve::inspect::CanonicalGoalEvaluationStep< + rustc_type_ir::solve::inspect::CanonicalGoalEvaluationStep< rustc_middle::ty::TyCtxt<'tcx> >, [] query_region_constraints: rustc_middle::infer::canonical::QueryRegionConstraints<'tcx>, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 639c98155e7..305ba1ef3bb 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,5 +1,3 @@ -use std::borrow::Cow; - use crate::hir::ModuleItems; use crate::middle::debugger_visualizer::DebuggerVisualizerFile; use crate::query::LocalCrate; @@ -256,26 +254,13 @@ impl<'hir> Map<'hir> { /// Given a `LocalDefId`, returns the `BodyId` associated with it, /// if the node is a body owner, otherwise returns `None`. - pub fn maybe_body_owned_by(self, id: LocalDefId) -> Option<Cow<'hir, Body<'hir>>> { - Some(match self.tcx.def_kind(id) { - // Inline consts do not have bodies of their own, so create one to make the follow-up logic simpler. - DefKind::InlineConst => { - let e = self.expect_expr(self.tcx.local_def_id_to_hir_id(id)); - Cow::Owned(Body { - params: &[], - value: match e.kind { - ExprKind::ConstBlock(body) => body, - _ => span_bug!(e.span, "InlineConst was not a ConstBlock: {e:#?}"), - }, - }) - } - _ => Cow::Borrowed(self.body(self.tcx.hir_node_by_def_id(id).body_id()?)), - }) + pub fn maybe_body_owned_by(self, id: LocalDefId) -> Option<&'hir Body<'hir>> { + Some(self.body(self.tcx.hir_node_by_def_id(id).body_id()?)) } /// Given a body owner's id, returns the `BodyId` associated with it. #[track_caller] - pub fn body_owned_by(self, id: LocalDefId) -> Cow<'hir, Body<'hir>> { + pub fn body_owned_by(self, id: LocalDefId) -> &'hir Body<'hir> { self.maybe_body_owned_by(id).unwrap_or_else(|| { let hir_id = self.tcx.local_def_id_to_hir_id(id); span_bug!( @@ -305,7 +290,9 @@ impl<'hir> Map<'hir> { DefKind::InlineConst => BodyOwnerKind::Const { inline: true }, DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn, DefKind::Closure => BodyOwnerKind::Closure, - DefKind::Static { mutability, nested: false } => BodyOwnerKind::Static(mutability), + DefKind::Static { safety: _, mutability, nested: false } => { + BodyOwnerKind::Static(mutability) + } dk => bug!("{:?} is not a body node: {:?}", def_id, dk), } } @@ -336,7 +323,7 @@ impl<'hir> Map<'hir> { /// Returns an iterator of the `DefId`s for all body-owners in this /// crate. If you would prefer to iterate over the bodies - /// themselves, you can do `self.hir().krate().owners.iter()`. + /// themselves, you can do `self.hir().krate().body_ids.iter()`. #[inline] pub fn body_owners(self) -> impl Iterator<Item = LocalDefId> + 'hir { self.tcx.hir_crate_items(()).body_owners.iter().copied() @@ -523,17 +510,7 @@ impl<'hir> Map<'hir> { /// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context. /// Used exclusively for diagnostics, to avoid suggestion function calls. pub fn is_inside_const_context(self, hir_id: HirId) -> bool { - for (_, node) in self.parent_iter(hir_id) { - if let Some((def_id, _)) = node.associated_body() { - return self.body_const_context(def_id).is_some(); - } - if let Node::Expr(e) = node { - if let ExprKind::ConstBlock(_) = e.kind { - return true; - } - } - } - false + self.body_const_context(self.enclosing_body_owner(hir_id)).is_some() } /// Retrieves the `HirId` for `id`'s enclosing function *if* the `id` block or return is @@ -886,7 +863,7 @@ impl<'hir> Map<'hir> { Node::Variant(variant) => named_span(variant.span, variant.ident, None), Node::ImplItem(item) => named_span(item.span, item.ident, Some(item.generics)), Node::ForeignItem(item) => match item.kind { - ForeignItemKind::Fn(decl, _, _) => until_within(item.span, decl.output.span()), + ForeignItemKind::Fn(decl, _, _, _) => until_within(item.span, decl.output.span()), _ => named_span(item.span, item.ident, None), }, Node::Ctor(_) => return self.span(self.tcx.parent_hir_id(hir_id)), @@ -916,6 +893,7 @@ impl<'hir> Map<'hir> { Node::Variant(variant) => variant.span, Node::Field(field) => field.span, Node::AnonConst(constant) => constant.span, + Node::ConstBlock(constant) => self.body(constant.body).value.span, Node::Expr(expr) => expr.span, Node::ExprField(field) => field.span, Node::Stmt(stmt) => stmt.span, @@ -1040,7 +1018,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { let krate = tcx.hir_crate(()); let hir_body_hash = krate.opt_hir_hash.expect("HIR hash missing while computing crate hash"); - let upstream_crates = upstream_crates_for_hashing(tcx); + let upstream_crates = upstream_crates(tcx); let resolutions = tcx.resolutions(()); @@ -1109,9 +1087,9 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { Svh::new(crate_hash) } -fn upstream_crates_for_hashing(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> { +fn upstream_crates(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> { let mut upstream_crates: Vec<_> = tcx - .crates_including_speculative(()) + .crates(()) .iter() .map(|&cnum| { let stable_crate_id = tcx.stable_crate_id(cnum); @@ -1185,6 +1163,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { format!("{id} (field `{}` in {})", field.ident, path_str(field.def_id)) } Node::AnonConst(_) => node_str("const"), + Node::ConstBlock(_) => node_str("const"), Node::Expr(_) => node_str("expr"), Node::ExprField(_) => node_str("expr field"), Node::Stmt(_) => node_str("stmt"), @@ -1334,6 +1313,11 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { intravisit::walk_anon_const(self, c) } + fn visit_inline_const(&mut self, c: &'hir ConstBlock) { + self.body_owners.push(c.def_id); + intravisit::walk_inline_const(self, c) + } + fn visit_expr(&mut self, ex: &'hir Expr<'hir>) { if let ExprKind::Closure(closure) = ex.kind { self.body_owners.push(closure.def_id); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index b0c14cdfec9..57c8ba96a20 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -201,7 +201,7 @@ pub fn provide(providers: &mut Providers) { .. }) | Node::ForeignItem(&ForeignItem { - kind: ForeignItemKind::Fn(_, idents, _), + kind: ForeignItemKind::Fn(_, idents, _, _), .. }) = tcx.hir_node(tcx.local_def_id_to_hir_id(def_id)) { diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index 105be21f272..a5da7e7739e 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -86,21 +86,6 @@ impl<'tcx> UnifyValue for RegionVariableValue<'tcx> { } } -impl ToType for ty::IntVarValue { - fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match *self { - ty::IntType(i) => Ty::new_int(tcx, i), - ty::UintType(i) => Ty::new_uint(tcx, i), - } - } -} - -impl ToType for ty::FloatVarValue { - fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - Ty::new_float(tcx, self.0) - } -} - // Generic consts. #[derive(Copy, Clone, Debug)] @@ -211,6 +196,7 @@ impl<'tcx> EffectVarValue<'tcx> { impl<'tcx> UnifyValue for EffectVarValue<'tcx> { type Error = NoError; + fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> { match (*value1, *value2) { (EffectVarValue::Unknown, EffectVarValue::Unknown) => Ok(EffectVarValue::Unknown), diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index d47e393c912..b499604df87 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -4,15 +4,16 @@ //! has their own README with further details). //! //! - **HIR.** The "high-level (H) intermediate representation (IR)" is -//! defined in the `hir` module. +//! defined in the [`hir`] module. //! - **MIR.** The "mid-level (M) intermediate representation (IR)" is -//! defined in the `mir` module. This module contains only the +//! defined in the [`mir`] module. This module contains only the //! *definition* of the MIR; the passes that transform and operate //! on MIR are found in `rustc_const_eval` crate. //! - **Types.** The internal representation of types used in rustc is -//! defined in the `ty` module. This includes the **type context** -//! (or `tcx`), which is the central context during most of -//! compilation, containing the interners and other things. +//! defined in the [`ty`] module. This includes the +//! [**type context**][ty::TyCtxt] (or `tcx`), which is the central +//! context during most of compilation, containing the interners and +//! other things. //! //! For more information about how rustc works, see the [rustc dev guide]. //! diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index e107c2c12bd..89f5acacf9d 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -84,11 +84,11 @@ impl<'tcx> ConstValue<'tcx> { } pub fn try_to_scalar_int(&self) -> Option<ScalarInt> { - self.try_to_scalar()?.try_to_int().ok() + self.try_to_scalar()?.try_to_scalar_int().ok() } pub fn try_to_bits(&self, size: Size) -> Option<u128> { - self.try_to_scalar_int()?.try_to_bits(size).ok() + Some(self.try_to_scalar_int()?.to_bits(size)) } pub fn try_to_bool(&self) -> Option<bool> { @@ -96,7 +96,7 @@ impl<'tcx> ConstValue<'tcx> { } pub fn try_to_target_usize(&self, tcx: TyCtxt<'tcx>) -> Option<u64> { - self.try_to_scalar_int()?.try_to_target_usize(tcx).ok() + Some(self.try_to_scalar_int()?.to_target_usize(tcx)) } pub fn try_to_bits_for_ty( @@ -204,7 +204,9 @@ pub enum Const<'tcx> { /// Any way of turning `ty::Const` into `ConstValue` should go through `valtree_to_const_val`; /// this ensures that we consistently produce "clean" values without data in the padding or /// anything like that. - Ty(ty::Const<'tcx>), + /// + /// FIXME(BoxyUwU): We should remove this `Ty` and look up the type for params via `ParamEnv` + Ty(Ty<'tcx>, ty::Const<'tcx>), /// An unevaluated mir constant which is not part of the type system. /// @@ -237,7 +239,15 @@ impl<'tcx> Const<'tcx> { #[inline(always)] pub fn ty(&self) -> Ty<'tcx> { match self { - Const::Ty(c) => c.ty(), + Const::Ty(ty, ct) => { + match ct.kind() { + // Dont use the outter ty as on invalid code we can wind up with them not being the same. + // this then results in allowing const eval to add `1_i64 + 1_usize` in cases where the mir + // was originally `({N: usize} + 1_usize)` under `generic_const_exprs`. + ty::ConstKind::Value(ty, _) => ty, + _ => *ty, + } + } Const::Val(_, ty) | Const::Unevaluated(_, ty) => *ty, } } @@ -247,8 +257,8 @@ impl<'tcx> Const<'tcx> { #[inline] pub fn is_required_const(&self) -> bool { match self { - Const::Ty(c) => match c.kind() { - ty::ConstKind::Value(_) => false, // already a value, cannot error + Const::Ty(_, c) => match c.kind() { + ty::ConstKind::Value(_, _) => false, // already a value, cannot error _ => true, }, Const::Val(..) => false, // already a value, cannot error @@ -259,8 +269,8 @@ impl<'tcx> Const<'tcx> { #[inline] pub fn try_to_scalar(self) -> Option<Scalar> { match self { - Const::Ty(c) => match c.kind() { - ty::ConstKind::Value(valtree) if c.ty().is_primitive() => { + Const::Ty(_, c) => match c.kind() { + ty::ConstKind::Value(ty, valtree) if ty.is_primitive() => { // A valtree of a type where leaves directly represent the scalar const value. // Just checking whether it is a leaf is insufficient as e.g. references are leafs // but the leaf value is the value they point to, not the reference itself! @@ -278,8 +288,8 @@ impl<'tcx> Const<'tcx> { // This is equivalent to `self.try_to_scalar()?.try_to_int().ok()`, but measurably faster. match self { Const::Val(ConstValue::Scalar(Scalar::Int(x)), _) => Some(x), - Const::Ty(c) => match c.kind() { - ty::ConstKind::Value(valtree) if c.ty().is_primitive() => { + Const::Ty(_, c) => match c.kind() { + ty::ConstKind::Value(ty, valtree) if ty.is_primitive() => { Some(valtree.unwrap_leaf()) } _ => None, @@ -290,7 +300,7 @@ impl<'tcx> Const<'tcx> { #[inline] pub fn try_to_bits(self, size: Size) -> Option<u128> { - self.try_to_scalar_int()?.try_to_bits(size).ok() + Some(self.try_to_scalar_int()?.to_bits(size)) } #[inline] @@ -306,11 +316,11 @@ impl<'tcx> Const<'tcx> { span: Span, ) -> Result<ConstValue<'tcx>, ErrorHandled> { match self { - Const::Ty(c) => { + Const::Ty(_, c) => { // We want to consistently have a "clean" value for type system constants (i.e., no // data hidden in the padding), so we always go through a valtree here. - let val = c.eval(tcx, param_env, span)?; - Ok(tcx.valtree_to_const_val((self.ty(), val))) + let (ty, val) = c.eval(tcx, param_env, span)?; + Ok(tcx.valtree_to_const_val((ty, val))) } Const::Unevaluated(uneval, _) => { // FIXME: We might want to have a `try_eval`-like function on `Unevaluated` @@ -326,7 +336,7 @@ impl<'tcx> Const<'tcx> { match self.eval(tcx, param_env, DUMMY_SP) { Ok(val) => Self::Val(val, self.ty()), Err(ErrorHandled::Reported(guar, _span)) => { - Self::Ty(ty::Const::new_error(tcx, guar.into(), self.ty())) + Self::Ty(Ty::new_error(tcx, guar.into()), ty::Const::new_error(tcx, guar.into())) } Err(ErrorHandled::TooGeneric(_span)) => self, } @@ -338,15 +348,16 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Option<Scalar> { - match self { - Const::Ty(c) if c.ty().is_primitive() => { - // Avoid the `valtree_to_const_val` query. Can only be done on primitive types that - // are valtree leaves, and *not* on references. (References should return the - // pointer here, which valtrees don't represent.) - let val = c.eval(tcx, param_env, DUMMY_SP).ok()?; - Some(val.unwrap_leaf().into()) - } - _ => self.eval(tcx, param_env, DUMMY_SP).ok()?.try_to_scalar(), + if let Const::Ty(_, c) = self + && let ty::ConstKind::Value(ty, val) = c.kind() + && ty.is_primitive() + { + // Avoid the `valtree_to_const_val` query. Can only be done on primitive types that + // are valtree leaves, and *not* on references. (References should return the + // pointer here, which valtrees don't represent.) + Some(val.unwrap_leaf().into()) + } else { + self.eval(tcx, param_env, DUMMY_SP).ok()?.try_to_scalar() } } @@ -356,7 +367,7 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Option<ScalarInt> { - self.try_eval_scalar(tcx, param_env)?.try_to_int().ok() + self.try_eval_scalar(tcx, param_env)?.try_to_scalar_int().ok() } #[inline] @@ -364,7 +375,7 @@ impl<'tcx> Const<'tcx> { let int = self.try_eval_scalar_int(tcx, param_env)?; let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size; - int.try_to_bits(size).ok() + Some(int.to_bits(size)) } /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type. @@ -380,7 +391,7 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> Option<u64> { - self.try_eval_scalar_int(tcx, param_env)?.try_to_target_usize(tcx).ok() + Some(self.try_eval_scalar_int(tcx, param_env)?.to_target_usize(tcx)) } #[inline] @@ -439,14 +450,14 @@ impl<'tcx> Const<'tcx> { Self::Val(val, ty) } - pub fn from_ty_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self { + pub fn from_ty_const(c: ty::Const<'tcx>, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Self { match c.kind() { - ty::ConstKind::Value(valtree) => { + ty::ConstKind::Value(ty, valtree) => { // Make sure that if `c` is normalized, then the return value is normalized. - let const_val = tcx.valtree_to_const_val((c.ty(), valtree)); - Self::Val(const_val, c.ty()) + let const_val = tcx.valtree_to_const_val((ty, valtree)); + Self::Val(const_val, ty) } - _ => Self::Ty(c), + _ => Self::Ty(ty, c), } } @@ -458,12 +469,12 @@ impl<'tcx> Const<'tcx> { // - valtrees purposefully generate new allocations // - ConstValue::Slice also generate new allocations match self { - Const::Ty(c) => match c.kind() { + Const::Ty(_, c) => match c.kind() { ty::ConstKind::Param(..) => true, // A valtree may be a reference. Valtree references correspond to a // different allocation each time they are evaluated. Valtrees for primitive // types are fine though. - ty::ConstKind::Value(_) => c.ty().is_primitive(), + ty::ConstKind::Value(ty, _) => ty.is_primitive(), ty::ConstKind::Unevaluated(..) | ty::ConstKind::Expr(..) => false, // This can happen if evaluation of a constant failed. The result does not matter // much since compilation is doomed. @@ -517,7 +528,7 @@ impl<'tcx> UnevaluatedConst<'tcx> { impl<'tcx> Display for Const<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { match *self { - Const::Ty(c) => pretty_print_const(c, fmt, true), + Const::Ty(_, c) => pretty_print_const(c, fmt, true), Const::Val(val, ty) => pretty_print_const_value(val, ty, fmt), // FIXME(valtrees): Correctly print mir constants. Const::Unevaluated(c, _ty) => { diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index fe743fa4aac..95857e8579d 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -1,4 +1,6 @@ -use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId}; +use super::{ + ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, GlobalId, +}; use crate::mir; use crate::query::TyCtxtEnsure; @@ -13,7 +15,7 @@ use tracing::{debug, instrument}; impl<'tcx> TyCtxt<'tcx> { /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts - /// that can't take any generic arguments like statics, const items or enum discriminants. If a + /// that can't take any generic arguments like const items or enum discriminants. If a /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. #[instrument(skip(self), level = "debug")] pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> { @@ -27,6 +29,24 @@ impl<'tcx> TyCtxt<'tcx> { let param_env = self.param_env(def_id).with_reveal_all_normalized(self); self.const_eval_global_id(param_env, cid, DUMMY_SP) } + + /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts + /// that can't take any generic arguments like const items or enum discriminants. If a + /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. + #[instrument(skip(self), level = "debug")] + pub fn const_eval_poly_to_alloc(self, def_id: DefId) -> EvalToAllocationRawResult<'tcx> { + // In some situations def_id will have generic parameters within scope, but they aren't allowed + // to be used. So we can't use `Instance::mono`, instead we feed unresolved generic parameters + // into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are + // encountered. + let args = GenericArgs::identity_for_item(self, def_id); + let instance = ty::Instance::new(def_id, args); + let cid = GlobalId { instance, promoted: None }; + let param_env = self.param_env(def_id).with_reveal_all_normalized(self); + let inputs = self.erase_regions(param_env.and(cid)); + self.eval_to_allocation_raw(inputs) + } + /// Resolves and evaluates a constant. /// /// The constant can be located on a trait like `<A as B>::C`, in which case the given @@ -177,7 +197,7 @@ impl<'tcx> TyCtxt<'tcx> { impl<'tcx> TyCtxtEnsure<'tcx> { /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts - /// that can't take any generic arguments like statics, const items or enum discriminants. If a + /// that can't take any generic arguments like const items or enum discriminants. If a /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. #[instrument(skip(self), level = "debug")] pub fn const_eval_poly(self, def_id: DefId) { diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index c5c87c506b7..70e5ad0635b 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -123,15 +123,11 @@ impl<Prov> Scalar<Prov> { } #[inline] - pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> { - ScalarInt::try_from_uint(i, size).map(Scalar::Int) - } - - #[inline] pub fn from_uint(i: impl Into<u128>, size: Size) -> Self { let i = i.into(); - Self::try_from_uint(i, size) + ScalarInt::try_from_uint(i, size) .unwrap_or_else(|| bug!("Unsigned value {:#x} does not fit in {} bits", i, size.bits())) + .into() } #[inline] @@ -165,15 +161,11 @@ impl<Prov> Scalar<Prov> { } #[inline] - pub fn try_from_int(i: impl Into<i128>, size: Size) -> Option<Self> { - ScalarInt::try_from_int(i, size).map(Scalar::Int) - } - - #[inline] pub fn from_int(i: impl Into<i128>, size: Size) -> Self { let i = i.into(); - Self::try_from_int(i, size) + ScalarInt::try_from_int(i, size) .unwrap_or_else(|| bug!("Signed value {:#x} does not fit in {} bits", i, size.bits())) + .into() } #[inline] @@ -197,6 +189,11 @@ impl<Prov> Scalar<Prov> { } #[inline] + pub fn from_i128(i: i128) -> Self { + Self::from_int(i, Size::from_bits(128)) + } + + #[inline] pub fn from_target_isize(i: i64, cx: &impl HasDataLayout) -> Self { Self::from_int(i, cx.data_layout().pointer_size) } @@ -222,7 +219,7 @@ impl<Prov> Scalar<Prov> { } /// This is almost certainly not the method you want! You should dispatch on the type - /// and use `to_{u8,u16,...}`/`scalar_to_ptr` to perform ptr-to-int / int-to-ptr casts as needed. + /// and use `to_{u8,u16,...}`/`to_pointer` to perform ptr-to-int / int-to-ptr casts as needed. /// /// This method only exists for the benefit of low-level operations that truly need to treat the /// scalar in whatever form it is. @@ -284,7 +281,7 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> { /// The error type is `AllocId`, not `CtfeProvenance`, since `AllocId` is the "minimal" /// component all provenance types must have. #[inline] - pub fn try_to_int(self) -> Result<ScalarInt, Scalar<AllocId>> { + pub fn try_to_scalar_int(self) -> Result<ScalarInt, Scalar<AllocId>> { match self { Scalar::Int(int) => Ok(int), Scalar::Ptr(ptr, sz) => { @@ -302,13 +299,13 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> { #[inline(always)] pub fn to_scalar_int(self) -> InterpResult<'tcx, ScalarInt> { - self.try_to_int().map_err(|_| err_unsup!(ReadPointerAsInt(None)).into()) + self.try_to_scalar_int().map_err(|_| err_unsup!(ReadPointerAsInt(None)).into()) } #[inline(always)] #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn assert_int(self) -> ScalarInt { - self.try_to_int().unwrap() + pub fn assert_scalar_int(self) -> ScalarInt { + self.try_to_scalar_int().expect("got a pointer where a ScalarInt was expected") } /// This throws UB (instead of ICEing) on a size mismatch since size mismatches can arise in @@ -325,13 +322,6 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> { }) } - #[inline(always)] - #[cfg_attr(debug_assertions, track_caller)] // only in debug builds due to perf (see #98980) - pub fn assert_bits(self, target_size: Size) -> u128 { - self.to_bits(target_size) - .unwrap_or_else(|_| panic!("assertion failed: {self:?} fits {target_size:?}")) - } - pub fn to_bool(self) -> InterpResult<'tcx, bool> { let val = self.to_u8()?; match val { diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index a3d2140eb1b..3d79ec0092f 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -5,9 +5,9 @@ use rustc_data_structures::base_n::BaseNString; use rustc_data_structures::base_n::ToBaseN; use rustc_data_structures::base_n::CASE_INSENSITIVE; use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; +use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher, ToStableHashKey}; +use rustc_data_structures::unord::UnordMap; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::ItemId; use rustc_index::Idx; @@ -241,7 +241,17 @@ impl<'tcx> fmt::Display for MonoItem<'tcx> { } } -#[derive(Debug)] +impl ToStableHashKey<StableHashingContext<'_>> for MonoItem<'_> { + type KeyType = Fingerprint; + + fn to_stable_hash_key(&self, hcx: &StableHashingContext<'_>) -> Self::KeyType { + let mut hasher = StableHasher::new(); + self.hash_stable(&mut hcx.clone(), &mut hasher); + hasher.finish() + } +} + +#[derive(Debug, HashStable)] pub struct CodegenUnit<'tcx> { /// A name for this CGU. Incremental compilation requires that /// name be unique amongst **all** crates. Therefore, it should @@ -430,38 +440,19 @@ impl<'tcx> CodegenUnit<'tcx> { } } -impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for CodegenUnit<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let CodegenUnit { - ref items, - name, - // The size estimate is not relevant to the hash - size_estimate: _, - primary: _, - is_code_coverage_dead_code_cgu, - } = *self; - - name.hash_stable(hcx, hasher); - is_code_coverage_dead_code_cgu.hash_stable(hcx, hasher); - - let mut items: Vec<(Fingerprint, _)> = items - .iter() - .map(|(mono_item, &attrs)| { - let mut hasher = StableHasher::new(); - mono_item.hash_stable(hcx, &mut hasher); - let mono_item_fingerprint = hasher.finish(); - (mono_item_fingerprint, attrs) - }) - .collect(); - - items.sort_unstable_by_key(|i| i.0); - items.hash_stable(hcx, hasher); +impl ToStableHashKey<StableHashingContext<'_>> for CodegenUnit<'_> { + type KeyType = String; + + fn to_stable_hash_key(&self, _: &StableHashingContext<'_>) -> Self::KeyType { + // Codegen unit names are conceptually required to be stable across + // compilation session so that object file names match up. + self.name.to_string() } } pub struct CodegenUnitNameBuilder<'tcx> { tcx: TyCtxt<'tcx>, - cache: FxHashMap<CrateNum, String>, + cache: UnordMap<CrateNum, String>, } impl<'tcx> CodegenUnitNameBuilder<'tcx> { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index f1c79c0b039..b64b7e2b1dc 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -559,10 +559,10 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io: match (kind, body.source.promoted) { (_, Some(_)) => write!(w, "const ")?, // promoteds are the closest to consts (DefKind::Const | DefKind::AssocConst, _) => write!(w, "const ")?, - (DefKind::Static { mutability: hir::Mutability::Not, nested: false }, _) => { + (DefKind::Static { safety: _, mutability: hir::Mutability::Not, nested: false }, _) => { write!(w, "static ")? } - (DefKind::Static { mutability: hir::Mutability::Mut, nested: false }, _) => { + (DefKind::Static { safety: _, mutability: hir::Mutability::Mut, nested: false }, _) => { write!(w, "static mut ")? } (_, _) if is_function => write!(w, "fn ")?, @@ -1313,12 +1313,12 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { }; let val = match const_ { - Const::Ty(ct) => match ct.kind() { + Const::Ty(_, ct) => match ct.kind() { ty::ConstKind::Param(p) => format!("ty::Param({p})"), ty::ConstKind::Unevaluated(uv) => { format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,) } - ty::ConstKind::Value(val) => format!("ty::Valtree({})", fmt_valtree(&val)), + ty::ConstKind::Value(_, val) => format!("ty::Valtree({})", fmt_valtree(&val)), // No `ty::` prefix since we also use this to represent errors from `mir::Unevaluated`. ty::ConstKind::Error(_) => "Error".to_string(), // These variants shouldn't exist in the MIR. @@ -1417,7 +1417,7 @@ pub fn write_allocations<'tcx>( impl<'tcx> Visitor<'tcx> for CollectAllocIds { fn visit_constant(&mut self, c: &ConstOperand<'tcx>, _: Location) { match c.const_ { - Const::Ty(_) | Const::Unevaluated(..) => {} + Const::Ty(_, _) | Const::Unevaluated(..) => {} Const::Val(val, _) => { self.0.extend(alloc_ids_from_const_val(val)); } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 8901fd42d93..f553b417294 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -895,7 +895,7 @@ macro_rules! make_mir_visitor { self.visit_span($(& $mutability)? *span); match const_ { - Const::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location), + Const::Ty(_, ct) => self.visit_ty_const($(&$mutability)? *ct, location), Const::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), Const::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index f98dbf8a0bd..b29a86d58ed 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -4,7 +4,7 @@ use crate::traits; use crate::ty::adjustment::CoerceUnsizedInfo; use crate::ty::{self, Ty}; use std::intrinsics::transmute_unchecked; -use std::mem::{size_of, MaybeUninit}; +use std::mem::MaybeUninit; #[derive(Copy, Clone)] pub struct Erased<T: Copy> { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d72ad09f954..a8bf735fa5a 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1309,7 +1309,7 @@ rustc_queries! { query object_safety_violations(trait_id: DefId) -> &'tcx [ObjectSafetyViolation] { desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) } } - query check_is_object_safe(trait_id: DefId) -> bool { + query is_object_safe(trait_id: DefId) -> bool { desc { |tcx| "checking if trait `{}` is object safe", tcx.def_path_str(trait_id) } } @@ -1494,6 +1494,11 @@ rustc_queries! { separate_provide_extern } + query specialization_enabled_in(cnum: CrateNum) -> bool { + desc { "checking whether the crate enabled `specialization`/`min_specialization`" } + separate_provide_extern + } + query specializes(_: (DefId, DefId)) -> bool { desc { "computing whether impls specialize one another" } } @@ -1861,22 +1866,13 @@ rustc_queries! { eval_always desc { "calculating the stability index for the local crate" } } - /// All loaded crates, including those loaded purely for doc links or diagnostics. - /// (Diagnostics include lints, so speculatively loaded crates may occur in successful - /// compilation even without doc links.) - /// Should be used when encoding crate metadata (and therefore when generating crate hash, - /// depinfo and similar things), to avoid dangling crate references in other encoded data, - /// like source maps. - /// May also be used for diagnostics - if we are loading a crate anyway we can suggest some - /// items from it as well. - /// But otherwise, `used_crates` should generally be used. - query crates_including_speculative(_: ()) -> &'tcx [CrateNum] { + query crates(_: ()) -> &'tcx [CrateNum] { eval_always desc { "fetching all foreign CrateNum instances" } } - /// Crates that are loaded non-speculatively (not for diagnostics or doc links). - /// Should be used to maintain observable language behavior, for example when collecting lang - /// items or impls from all crates, or collecting libraries to link. + // Crates that are loaded non-speculatively (not for diagnostics or doc links). + // FIXME: This is currently only used for collecting lang items, but should be used instead of + // `crates` in most other cases too. query used_crates(_: ()) -> &'tcx [CrateNum] { eval_always desc { "fetching `CrateNum`s for all crates loaded non-speculatively" } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 454897aa672..7c8b0ec671a 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -1033,8 +1033,8 @@ impl<'tcx> PatRangeBoundary<'tcx> { if let (Some(a), Some(b)) = (a.try_to_scalar_int(), b.try_to_scalar_int()) { let sz = ty.primitive_size(tcx); let cmp = match ty.kind() { - ty::Uint(_) | ty::Char => a.assert_uint(sz).cmp(&b.assert_uint(sz)), - ty::Int(_) => a.assert_int(sz).cmp(&b.assert_int(sz)), + ty::Uint(_) | ty::Char => a.to_uint(sz).cmp(&b.to_uint(sz)), + ty::Int(_) => a.to_int(sz).cmp(&b.to_int(sz)), _ => unreachable!(), }; return Some(cmp); diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 62e71c4db11..202d587f0ad 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -32,7 +32,7 @@ use std::hash::{Hash, Hasher}; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; // FIXME: Remove this import and import via `solve::` -pub use rustc_next_trait_solver::solve::BuiltinImplSource; +pub use rustc_type_ir::solve::BuiltinImplSource; /// Depending on the stage of compilation, we want projection to be /// more or less conservative. @@ -616,6 +616,8 @@ pub enum SelectionError<'tcx> { /// We can thus not know whether the hidden type implements an auto trait, so /// we should not presume anything about it. OpaqueTypeAutoTraitLeakageUnknown(DefId), + /// Error for a `ConstArgHasType` goal + ConstArgHasWrongType { ct: ty::Const<'tcx>, ct_ty: Ty<'tcx>, expected_ty: Ty<'tcx> }, } #[derive(Clone, Debug, TypeVisitable)] diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 66e50307733..50b6c77e1b2 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -7,13 +7,12 @@ use crate::error::DropCheckOverflow; use crate::infer::canonical::{Canonical, QueryResponse}; -use crate::ty::error::TypeError; use crate::ty::GenericArg; use crate::ty::{self, Ty, TyCtxt}; use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; use rustc_span::Span; // FIXME: Remove this import and import via `traits::solve`. -pub use rustc_next_trait_solver::solve::NoSolution; +pub use rustc_type_ir::solve::NoSolution; pub mod type_op { use crate::ty::fold::TypeFoldable; @@ -91,12 +90,6 @@ pub type CanonicalTypeOpProvePredicateGoal<'tcx> = pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>; -impl<'tcx> From<TypeError<'tcx>> for NoSolution { - fn from(_: TypeError<'tcx>) -> NoSolution { - NoSolution - } -} - #[derive(Clone, Debug, Default, HashStable, TypeFoldable, TypeVisitable)] pub struct DropckOutlivesResult<'tcx> { pub kinds: Vec<GenericArg<'tcx>>, diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index c8c16ec1e2c..0d9ce402c64 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -1,8 +1,8 @@ use rustc_ast_ir::try_visit; use rustc_data_structures::intern::Interned; use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; -use rustc_next_trait_solver as ir; -pub use rustc_next_trait_solver::solve::*; +use rustc_type_ir as ir; +pub use rustc_type_ir::solve::*; use crate::infer::canonical::QueryRegionConstraints; use crate::ty::{ diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index 7fb5e9aadae..254e1b54481 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -53,7 +53,7 @@ impl<'tcx> TyCtxt<'tcx> { fn fold_const(&mut self, c: Const<'tcx>) -> Const<'tcx> { let ct = match c.kind() { ty::ConstKind::Unevaluated(uv) => match self.tcx.thir_abstract_const(uv.def) { - Err(e) => ty::Const::new_error(self.tcx, e, c.ty()), + Err(e) => ty::Const::new_error(self.tcx, e), Ok(Some(bac)) => { let args = self.tcx.erase_regions(uv.args); let bac = bac.instantiate(self.tcx, args); diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 5f9b870331c..886dbd317af 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -200,6 +200,12 @@ impl<'tcx> AdtDef<'tcx> { } } +impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> { + fn def_id(self) -> DefId { + self.did() + } +} + #[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable, TyEncodable, TyDecodable)] pub enum AdtKind { Struct, diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 07652b47929..33f564e9b59 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -350,8 +350,8 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Const<'tcx> { fn decode(decoder: &mut D) -> Self { - let consts: ty::ConstData<'tcx> = Decodable::decode(decoder); - decoder.interner().mk_ct_from_kind(consts.kind, consts.ty) + let kind: ty::ConstKind<'tcx> = Decodable::decode(decoder); + decoder.interner().mk_ct_from_kind(kind) } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 6416bbbe889..12f0c38b054 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -6,7 +6,7 @@ use rustc_error_messages::MultiSpan; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; -use rustc_macros::{HashStable, TyDecodable, TyEncodable}; +use rustc_macros::HashStable; use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; use tracing::{debug, instrument}; @@ -26,10 +26,9 @@ pub type UnevaluatedConst<'tcx> = ir::UnevaluatedConst<TyCtxt<'tcx>>; #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(ConstKind<'_>, 32); -/// Use this rather than `ConstData`, whenever possible. #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)] #[rustc_pass_by_value] -pub struct Const<'tcx>(pub(super) Interned<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>); +pub struct Const<'tcx>(pub(super) Interned<'tcx, WithCachedTypeInfo<ConstKind<'tcx>>>); impl<'tcx> rustc_type_ir::inherent::IntoKind for Const<'tcx> { type Kind = ConstKind<'tcx>; @@ -49,26 +48,11 @@ impl<'tcx> rustc_type_ir::visit::Flags for Const<'tcx> { } } -/// Typed constant value. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -#[derive(HashStable, TyEncodable, TyDecodable)] -pub struct ConstData<'tcx> { - pub ty: Ty<'tcx>, - pub kind: ConstKind<'tcx>, -} - -#[cfg(target_pointer_width = "64")] -rustc_data_structures::static_assert_size!(ConstData<'_>, 40); - impl<'tcx> Const<'tcx> { #[inline] - pub fn ty(self) -> Ty<'tcx> { - self.0.ty - } - - #[inline] pub fn kind(self) -> ConstKind<'tcx> { - self.0.kind + let a: &ConstKind<'tcx> = self.0.0; + *a } // FIXME(compiler-errors): Think about removing this. @@ -84,28 +68,28 @@ impl<'tcx> Const<'tcx> { } #[inline] - pub fn new(tcx: TyCtxt<'tcx>, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { - tcx.mk_ct_from_kind(kind, ty) + pub fn new(tcx: TyCtxt<'tcx>, kind: ty::ConstKind<'tcx>) -> Const<'tcx> { + tcx.mk_ct_from_kind(kind) } #[inline] - pub fn new_param(tcx: TyCtxt<'tcx>, param: ty::ParamConst, ty: Ty<'tcx>) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Param(param), ty) + pub fn new_param(tcx: TyCtxt<'tcx>, param: ty::ParamConst) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Param(param)) } #[inline] - pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid, ty: Ty<'tcx>) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Var(infer)), ty) + pub fn new_var(tcx: TyCtxt<'tcx>, infer: ty::ConstVid) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Var(infer))) } #[inline] - pub fn new_fresh(tcx: TyCtxt<'tcx>, fresh: u32, ty: Ty<'tcx>) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Fresh(fresh)), ty) + pub fn new_fresh(tcx: TyCtxt<'tcx>, fresh: u32) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Infer(ty::InferConst::Fresh(fresh))) } #[inline] - pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst, ty: Ty<'tcx>) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Infer(infer), ty) + pub fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Infer(infer)) } #[inline] @@ -113,50 +97,40 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar, - ty: Ty<'tcx>, ) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Bound(debruijn, var), ty) + Const::new(tcx, ty::ConstKind::Bound(debruijn, var)) } #[inline] - pub fn new_placeholder( - tcx: TyCtxt<'tcx>, - placeholder: ty::PlaceholderConst, - ty: Ty<'tcx>, - ) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Placeholder(placeholder), ty) + pub fn new_placeholder(tcx: TyCtxt<'tcx>, placeholder: ty::PlaceholderConst) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Placeholder(placeholder)) } #[inline] - pub fn new_unevaluated( - tcx: TyCtxt<'tcx>, - uv: ty::UnevaluatedConst<'tcx>, - ty: Ty<'tcx>, - ) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Unevaluated(uv), ty) + pub fn new_unevaluated(tcx: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Unevaluated(uv)) } #[inline] pub fn new_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Value(val), ty) + Const::new(tcx, ty::ConstKind::Value(ty, val)) } #[inline] - pub fn new_expr(tcx: TyCtxt<'tcx>, expr: ty::Expr<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Expr(expr), ty) + pub fn new_expr(tcx: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Expr(expr)) } #[inline] - pub fn new_error(tcx: TyCtxt<'tcx>, e: ty::ErrorGuaranteed, ty: Ty<'tcx>) -> Const<'tcx> { - Const::new(tcx, ty::ConstKind::Error(e), ty) + pub fn new_error(tcx: TyCtxt<'tcx>, e: ty::ErrorGuaranteed) -> Const<'tcx> { + Const::new(tcx, ty::ConstKind::Error(e)) } /// Like [Ty::new_error] but for constants. #[track_caller] - pub fn new_misc_error(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + pub fn new_misc_error(tcx: TyCtxt<'tcx>) -> Const<'tcx> { Const::new_error_with_message( tcx, - ty, DUMMY_SP, "ty::ConstKind::Error constructed but no error reported", ) @@ -166,52 +140,41 @@ impl<'tcx> Const<'tcx> { #[track_caller] pub fn new_error_with_message<S: Into<MultiSpan>>( tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, span: S, msg: &'static str, ) -> Const<'tcx> { let reported = tcx.dcx().span_delayed_bug(span, msg); - Const::new_error(tcx, reported, ty) + Const::new_error(tcx, reported) } } impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> { - fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst, ty: Ty<'tcx>) -> Self { - Const::new_infer(tcx, infer, ty) + fn try_to_target_usize(self, interner: TyCtxt<'tcx>) -> Option<u64> { + self.try_to_target_usize(interner) } - fn new_var(tcx: TyCtxt<'tcx>, vid: ty::ConstVid, ty: Ty<'tcx>) -> Self { - Const::new_var(tcx, vid, ty) + fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst) -> Self { + Const::new_infer(tcx, infer) } - fn new_bound( - interner: TyCtxt<'tcx>, - debruijn: ty::DebruijnIndex, - var: ty::BoundVar, - ty: Ty<'tcx>, - ) -> Self { - Const::new_bound(interner, debruijn, var, ty) + fn new_var(tcx: TyCtxt<'tcx>, vid: ty::ConstVid) -> Self { + Const::new_var(tcx, vid) } - fn new_anon_bound( - tcx: TyCtxt<'tcx>, - debruijn: ty::DebruijnIndex, - var: ty::BoundVar, - ty: Ty<'tcx>, - ) -> Self { - Const::new_bound(tcx, debruijn, var, ty) + fn new_bound(interner: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { + Const::new_bound(interner, debruijn, var) } - fn new_unevaluated( - interner: TyCtxt<'tcx>, - uv: ty::UnevaluatedConst<'tcx>, - ty: Ty<'tcx>, - ) -> Self { - Const::new_unevaluated(interner, uv, ty) + fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self { + Const::new_bound(tcx, debruijn, var) } - fn ty(self) -> Ty<'tcx> { - self.ty() + fn new_unevaluated(interner: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Self { + Const::new_unevaluated(interner, uv) + } + + fn new_expr(interner: TyCtxt<'tcx>, expr: ty::Expr<'tcx>) -> Self { + Const::new_expr(interner, expr) } } @@ -241,7 +204,6 @@ impl<'tcx> Const<'tcx> { def: def.to_def_id(), args: GenericArgs::identity_for_item(tcx, def.to_def_id()), }, - ty, ), } } @@ -293,9 +255,6 @@ impl<'tcx> Const<'tcx> { _, &hir::Path { res: Res::Def(DefKind::ConstParam, def_id), .. }, )) => { - // Use the type from the param's definition, since we can resolve it, - // not the expected parameter type from WithOptConstParam. - let param_ty = tcx.type_of(def_id).instantiate_identity(); match tcx.named_bound_var(expr.hir_id) { Some(rbv::ResolvedArg::EarlyBound(_)) => { // Find the name and index of the const parameter by indexing the generics of @@ -304,19 +263,12 @@ impl<'tcx> Const<'tcx> { let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; let name = tcx.item_name(def_id); - Some(ty::Const::new_param(tcx, ty::ParamConst::new(index, name), param_ty)) + Some(ty::Const::new_param(tcx, ty::ParamConst::new(index, name))) } Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { - Some(ty::Const::new_bound( - tcx, - debruijn, - ty::BoundVar::from_u32(index), - param_ty, - )) - } - Some(rbv::ResolvedArg::Error(guar)) => { - Some(ty::Const::new_error(tcx, guar, param_ty)) + Some(ty::Const::new_bound(tcx, debruijn, ty::BoundVar::from_u32(index))) } + Some(rbv::ResolvedArg::Error(guar)) => Some(ty::Const::new_error(tcx, guar)), arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id), } } @@ -363,7 +315,7 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, span: Span, - ) -> Result<ValTree<'tcx>, ErrorHandled> { + ) -> Result<(Ty<'tcx>, ValTree<'tcx>), ErrorHandled> { assert!(!self.has_escaping_bound_vars(), "escaping vars in {self:?}"); match self.kind() { ConstKind::Unevaluated(unevaluated) => { @@ -381,9 +333,9 @@ impl<'tcx> Const<'tcx> { ); return Err(e.into()); }; - Ok(c) + Ok((tcx.type_of(unevaluated.def).instantiate(tcx, unevaluated.args), c)) } - ConstKind::Value(val) => Ok(val), + ConstKind::Value(ty, val) => Ok((ty, val)), ConstKind::Error(g) => Err(g.into()), ConstKind::Param(_) | ConstKind::Infer(_) @@ -397,8 +349,8 @@ impl<'tcx> Const<'tcx> { #[inline] pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self { match self.eval(tcx, param_env, DUMMY_SP) { - Ok(val) => Self::new_value(tcx, val, self.ty()), - Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into(), self.ty()), + Ok((ty, val)) => Self::new_value(tcx, val, ty), + Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into()), Err(ErrorHandled::TooGeneric(_span)) => self, } } @@ -408,8 +360,10 @@ impl<'tcx> Const<'tcx> { self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - ) -> Option<Scalar> { - self.eval(tcx, param_env, DUMMY_SP).ok()?.try_to_scalar() + ) -> Option<(Ty<'tcx>, Scalar)> { + let (ty, val) = self.eval(tcx, param_env, DUMMY_SP).ok()?; + let val = val.try_to_scalar()?; + Some((ty, val)) } #[inline] @@ -420,8 +374,10 @@ impl<'tcx> Const<'tcx> { self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, - ) -> Option<ScalarInt> { - self.try_eval_scalar(tcx, param_env)?.try_to_int().ok() + ) -> Option<(Ty<'tcx>, ScalarInt)> { + let (ty, scalar) = self.try_eval_scalar(tcx, param_env)?; + let val = scalar.try_to_scalar_int().ok()?; + Some((ty, val)) } #[inline] @@ -429,18 +385,17 @@ impl<'tcx> Const<'tcx> { /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it /// contains const generic parameters or pointers). pub fn try_eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u128> { - let int = self.try_eval_scalar_int(tcx, param_env)?; - let size = - tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size; + let (ty, scalar) = self.try_eval_scalar_int(tcx, param_env)?; + let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size; // if `ty` does not depend on generic parameters, use an empty param_env - int.try_to_bits(size).ok() + Some(scalar.to_bits(size)) } #[inline] /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type. pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u128 { self.try_eval_bits(tcx, param_env) - .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self)) + .unwrap_or_else(|| bug!("failed to evalate {:#?} to bits", self)) } #[inline] @@ -449,12 +404,14 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ) -> Option<u64> { - self.try_eval_scalar_int(tcx, param_env)?.try_to_target_usize(tcx).ok() + let (_, scalar) = self.try_eval_scalar_int(tcx, param_env)?; + Some(scalar.to_target_usize(tcx)) } #[inline] pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> { - self.try_eval_scalar_int(tcx, param_env)?.try_into().ok() + let (_, scalar) = self.try_eval_scalar_int(tcx, param_env)?; + scalar.try_into().ok() } #[inline] @@ -467,7 +424,7 @@ impl<'tcx> Const<'tcx> { /// Panics if self.kind != ty::ConstKind::Value pub fn to_valtree(self) -> ty::ValTree<'tcx> { match self.kind() { - ty::ConstKind::Value(valtree) => valtree, + ty::ConstKind::Value(_, valtree) => valtree, _ => bug!("expected ConstKind::Value, got {:?}", self.kind()), } } @@ -475,7 +432,7 @@ impl<'tcx> Const<'tcx> { /// Attempts to convert to a `ValTree` pub fn try_to_valtree(self) -> Option<ty::ValTree<'tcx>> { match self.kind() { - ty::ConstKind::Value(valtree) => Some(valtree), + ty::ConstKind::Value(_, valtree) => Some(valtree), _ => None, } } diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 40ac87873a0..52320dd141b 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -246,6 +246,10 @@ impl ScalarInt { Self::try_from_uint(i, tcx.data_layout.pointer_size) } + /// Try to convert this ScalarInt to the raw underlying bits. + /// Fails if the size is wrong. Generally a wrong size should lead to a panic, + /// but Miri sometimes wants to be resilient to size mismatches, + /// so the interpreter will generally use this `try` method. #[inline] pub fn try_to_bits(self, target_size: Size) -> Result<u128, Size> { assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST"); @@ -258,165 +262,149 @@ impl ScalarInt { } #[inline] - pub fn assert_bits(self, target_size: Size) -> u128 { + pub fn to_bits(self, target_size: Size) -> u128 { self.try_to_bits(target_size).unwrap_or_else(|size| { bug!("expected int of size {}, but got size {}", target_size.bytes(), size.bytes()) }) } - /// Tries to convert the `ScalarInt` to an unsigned integer of the given size. - /// Fails if the size of the `ScalarInt` is not equal to `size` and returns the - /// `ScalarInt`s size in that case. + /// Extracts the bits from the scalar without checking the size. #[inline] - pub fn try_to_uint(self, size: Size) -> Result<u128, Size> { - self.try_to_bits(size) + pub fn to_bits_unchecked(self) -> u128 { + self.check_data(); + self.data } + /// Converts the `ScalarInt` to an unsigned integer of the given size. + /// Panics if the size of the `ScalarInt` is not equal to `size`. #[inline] - pub fn assert_uint(self, size: Size) -> u128 { - self.assert_bits(size) + pub fn to_uint(self, size: Size) -> u128 { + self.to_bits(size) } - // Tries to convert the `ScalarInt` to `u8`. Fails if the `size` of the `ScalarInt` - // in not equal to 1 byte and returns the `size` value of the `ScalarInt` in - // that case. + /// Converts the `ScalarInt` to `u8`. + /// Panics if the `size` of the `ScalarInt`in not equal to 1 byte. #[inline] - pub fn try_to_u8(self) -> Result<u8, Size> { - self.try_to_uint(Size::from_bits(8)).map(|v| u8::try_from(v).unwrap()) + pub fn to_u8(self) -> u8 { + self.to_uint(Size::from_bits(8)).try_into().unwrap() } - /// Tries to convert the `ScalarInt` to `u16`. Fails if the size of the `ScalarInt` - /// in not equal to 2 bytes and returns the `size` value of the `ScalarInt` in - /// that case. + /// Converts the `ScalarInt` to `u16`. + /// Panics if the size of the `ScalarInt` in not equal to 2 bytes. #[inline] - pub fn try_to_u16(self) -> Result<u16, Size> { - self.try_to_uint(Size::from_bits(16)).map(|v| u16::try_from(v).unwrap()) + pub fn to_u16(self) -> u16 { + self.to_uint(Size::from_bits(16)).try_into().unwrap() } - /// Tries to convert the `ScalarInt` to `u32`. Fails if the `size` of the `ScalarInt` - /// in not equal to 4 bytes and returns the `size` value of the `ScalarInt` in - /// that case. + /// Converts the `ScalarInt` to `u32`. + /// Panics if the `size` of the `ScalarInt` in not equal to 4 bytes. #[inline] - pub fn try_to_u32(self) -> Result<u32, Size> { - self.try_to_uint(Size::from_bits(32)).map(|v| u32::try_from(v).unwrap()) + pub fn to_u32(self) -> u32 { + self.to_uint(Size::from_bits(32)).try_into().unwrap() } - /// Tries to convert the `ScalarInt` to `u64`. Fails if the `size` of the `ScalarInt` - /// in not equal to 8 bytes and returns the `size` value of the `ScalarInt` in - /// that case. + /// Converts the `ScalarInt` to `u64`. + /// Panics if the `size` of the `ScalarInt` in not equal to 8 bytes. #[inline] - pub fn try_to_u64(self) -> Result<u64, Size> { - self.try_to_uint(Size::from_bits(64)).map(|v| u64::try_from(v).unwrap()) + pub fn to_u64(self) -> u64 { + self.to_uint(Size::from_bits(64)).try_into().unwrap() } - /// Tries to convert the `ScalarInt` to `u128`. Fails if the `size` of the `ScalarInt` - /// in not equal to 16 bytes and returns the `size` value of the `ScalarInt` in - /// that case. + /// Converts the `ScalarInt` to `u128`. + /// Panics if the `size` of the `ScalarInt` in not equal to 16 bytes. #[inline] - pub fn try_to_u128(self) -> Result<u128, Size> { - self.try_to_uint(Size::from_bits(128)) + pub fn to_u128(self) -> u128 { + self.to_uint(Size::from_bits(128)) } #[inline] - pub fn try_to_target_usize(&self, tcx: TyCtxt<'_>) -> Result<u64, Size> { - self.try_to_uint(tcx.data_layout.pointer_size).map(|v| u64::try_from(v).unwrap()) + pub fn to_target_usize(&self, tcx: TyCtxt<'_>) -> u64 { + self.to_uint(tcx.data_layout.pointer_size).try_into().unwrap() } - // Tries to convert the `ScalarInt` to `bool`. Fails if the `size` of the `ScalarInt` - // in not equal to 1 byte or if the value is not 0 or 1 and returns the `size` - // value of the `ScalarInt` in that case. + /// Converts the `ScalarInt` to `bool`. + /// Panics if the `size` of the `ScalarInt` is not equal to 1 byte. + /// Errors if it is not a valid `bool`. #[inline] - pub fn try_to_bool(self) -> Result<bool, Size> { - match self.try_to_u8()? { + pub fn try_to_bool(self) -> Result<bool, ()> { + match self.to_u8() { 0 => Ok(false), 1 => Ok(true), - _ => Err(self.size()), + _ => Err(()), } } - /// Tries to convert the `ScalarInt` to a signed integer of the given size. - /// Fails if the size of the `ScalarInt` is not equal to `size` and returns the - /// `ScalarInt`s size in that case. - #[inline] - pub fn try_to_int(self, size: Size) -> Result<i128, Size> { - let b = self.try_to_bits(size)?; - Ok(size.sign_extend(b) as i128) - } - + /// Converts the `ScalarInt` to a signed integer of the given size. + /// Panics if the size of the `ScalarInt` is not equal to `size`. #[inline] - pub fn assert_int(self, size: Size) -> i128 { - let b = self.assert_bits(size); + pub fn to_int(self, size: Size) -> i128 { + let b = self.to_bits(size); size.sign_extend(b) as i128 } - /// Tries to convert the `ScalarInt` to i8. - /// Fails if the size of the `ScalarInt` is not equal to 1 byte - /// and returns the `ScalarInt`s size in that case. - pub fn try_to_i8(self) -> Result<i8, Size> { - self.try_to_int(Size::from_bits(8)).map(|v| i8::try_from(v).unwrap()) + /// Converts the `ScalarInt` to i8. + /// Panics if the size of the `ScalarInt` is not equal to 1 byte. + pub fn to_i8(self) -> i8 { + self.to_int(Size::from_bits(8)).try_into().unwrap() } - /// Tries to convert the `ScalarInt` to i16. - /// Fails if the size of the `ScalarInt` is not equal to 2 bytes - /// and returns the `ScalarInt`s size in that case. - pub fn try_to_i16(self) -> Result<i16, Size> { - self.try_to_int(Size::from_bits(16)).map(|v| i16::try_from(v).unwrap()) + /// Converts the `ScalarInt` to i16. + /// Panics if the size of the `ScalarInt` is not equal to 2 bytes. + pub fn to_i16(self) -> i16 { + self.to_int(Size::from_bits(16)).try_into().unwrap() } - /// Tries to convert the `ScalarInt` to i32. - /// Fails if the size of the `ScalarInt` is not equal to 4 bytes - /// and returns the `ScalarInt`s size in that case. - pub fn try_to_i32(self) -> Result<i32, Size> { - self.try_to_int(Size::from_bits(32)).map(|v| i32::try_from(v).unwrap()) + /// Converts the `ScalarInt` to i32. + /// Panics if the size of the `ScalarInt` is not equal to 4 bytes. + pub fn to_i32(self) -> i32 { + self.to_int(Size::from_bits(32)).try_into().unwrap() } - /// Tries to convert the `ScalarInt` to i64. - /// Fails if the size of the `ScalarInt` is not equal to 8 bytes - /// and returns the `ScalarInt`s size in that case. - pub fn try_to_i64(self) -> Result<i64, Size> { - self.try_to_int(Size::from_bits(64)).map(|v| i64::try_from(v).unwrap()) + /// Converts the `ScalarInt` to i64. + /// Panics if the size of the `ScalarInt` is not equal to 8 bytes. + pub fn to_i64(self) -> i64 { + self.to_int(Size::from_bits(64)).try_into().unwrap() } - /// Tries to convert the `ScalarInt` to i128. - /// Fails if the size of the `ScalarInt` is not equal to 16 bytes - /// and returns the `ScalarInt`s size in that case. - pub fn try_to_i128(self) -> Result<i128, Size> { - self.try_to_int(Size::from_bits(128)) + /// Converts the `ScalarInt` to i128. + /// Panics if the size of the `ScalarInt` is not equal to 16 bytes. + pub fn to_i128(self) -> i128 { + self.to_int(Size::from_bits(128)) } #[inline] - pub fn try_to_target_isize(&self, tcx: TyCtxt<'_>) -> Result<i64, Size> { - self.try_to_int(tcx.data_layout.pointer_size).map(|v| i64::try_from(v).unwrap()) + pub fn to_target_isize(&self, tcx: TyCtxt<'_>) -> i64 { + self.to_int(tcx.data_layout.pointer_size).try_into().unwrap() } #[inline] - pub fn try_to_float<F: Float>(self) -> Result<F, Size> { + pub fn to_float<F: Float>(self) -> F { // Going through `to_uint` to check size and truncation. - Ok(F::from_bits(self.try_to_bits(Size::from_bits(F::BITS))?)) + F::from_bits(self.to_bits(Size::from_bits(F::BITS))) } #[inline] - pub fn try_to_f16(self) -> Result<Half, Size> { - self.try_to_float() + pub fn to_f16(self) -> Half { + self.to_float() } #[inline] - pub fn try_to_f32(self) -> Result<Single, Size> { - self.try_to_float() + pub fn to_f32(self) -> Single { + self.to_float() } #[inline] - pub fn try_to_f64(self) -> Result<Double, Size> { - self.try_to_float() + pub fn to_f64(self) -> Double { + self.to_float() } #[inline] - pub fn try_to_f128(self) -> Result<Quad, Size> { - self.try_to_float() + pub fn to_f128(self) -> Quad { + self.to_float() } } -macro_rules! from { +macro_rules! from_x_for_scalar_int { ($($ty:ty),*) => { $( impl From<$ty> for ScalarInt { @@ -432,30 +420,29 @@ macro_rules! from { } } -macro_rules! try_from { +macro_rules! from_scalar_int_for_x { ($($ty:ty),*) => { $( - impl TryFrom<ScalarInt> for $ty { - type Error = Size; + impl From<ScalarInt> for $ty { #[inline] - fn try_from(int: ScalarInt) -> Result<Self, Size> { + fn from(int: ScalarInt) -> Self { // The `unwrap` cannot fail because to_bits (if it succeeds) // is guaranteed to return a value that fits into the size. - int.try_to_bits(Size::from_bytes(std::mem::size_of::<$ty>())) - .map(|u| u.try_into().unwrap()) + int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>())) + .try_into().unwrap() } } )* } } -from!(u8, u16, u32, u64, u128, bool); -try_from!(u8, u16, u32, u64, u128); +from_x_for_scalar_int!(u8, u16, u32, u64, u128, bool); +from_scalar_int_for_x!(u8, u16, u32, u64, u128); impl TryFrom<ScalarInt> for bool { - type Error = Size; + type Error = (); #[inline] - fn try_from(int: ScalarInt) -> Result<Self, Size> { + fn try_from(int: ScalarInt) -> Result<Self, ()> { int.try_to_bool() } } @@ -463,7 +450,7 @@ impl TryFrom<ScalarInt> for bool { impl From<char> for ScalarInt { #[inline] fn from(c: char) -> Self { - Self { data: c as u128, size: NonZero::new(std::mem::size_of::<char>() as u8).unwrap() } + (c as u32).into() } } @@ -476,10 +463,7 @@ impl TryFrom<ScalarInt> for char { #[inline] fn try_from(int: ScalarInt) -> Result<Self, Self::Error> { - let Ok(bits) = int.try_to_bits(Size::from_bytes(std::mem::size_of::<char>())) else { - return Err(CharTryFromScalarInt); - }; - match char::from_u32(bits.try_into().unwrap()) { + match char::from_u32(int.to_u32()) { Some(c) => Ok(c), None => Err(CharTryFromScalarInt), } @@ -494,11 +478,10 @@ impl From<Half> for ScalarInt { } } -impl TryFrom<ScalarInt> for Half { - type Error = Size; +impl From<ScalarInt> for Half { #[inline] - fn try_from(int: ScalarInt) -> Result<Self, Size> { - int.try_to_bits(Size::from_bytes(2)).map(Self::from_bits) + fn from(int: ScalarInt) -> Self { + Self::from_bits(int.to_bits(Size::from_bytes(2))) } } @@ -510,11 +493,10 @@ impl From<Single> for ScalarInt { } } -impl TryFrom<ScalarInt> for Single { - type Error = Size; +impl From<ScalarInt> for Single { #[inline] - fn try_from(int: ScalarInt) -> Result<Self, Size> { - int.try_to_bits(Size::from_bytes(4)).map(Self::from_bits) + fn from(int: ScalarInt) -> Self { + Self::from_bits(int.to_bits(Size::from_bytes(4))) } } @@ -526,11 +508,10 @@ impl From<Double> for ScalarInt { } } -impl TryFrom<ScalarInt> for Double { - type Error = Size; +impl From<ScalarInt> for Double { #[inline] - fn try_from(int: ScalarInt) -> Result<Self, Size> { - int.try_to_bits(Size::from_bytes(8)).map(Self::from_bits) + fn from(int: ScalarInt) -> Self { + Self::from_bits(int.to_bits(Size::from_bytes(8))) } } @@ -542,11 +523,10 @@ impl From<Quad> for ScalarInt { } } -impl TryFrom<ScalarInt> for Quad { - type Error = Size; +impl From<ScalarInt> for Quad { #[inline] - fn try_from(int: ScalarInt) -> Result<Self, Size> { - int.try_to_bits(Size::from_bytes(16)).map(Self::from_bits) + fn from(int: ScalarInt) -> Self { + Self::from_bits(int.to_bits(Size::from_bytes(16))) } } diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index d7ae050ed4d..bf834ef7607 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -1,7 +1,7 @@ use super::Const; use crate::mir; use crate::ty::abstract_const::CastKind; -use crate::ty::{self, visit::TypeVisitableExt as _, List, Ty, TyCtxt}; +use crate::ty::{self, visit::TypeVisitableExt as _, Ty, TyCtxt}; use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; #[extension(pub(crate) trait UnevaluatedConstEvalExt<'tcx>)] @@ -40,14 +40,127 @@ impl<'tcx> ty::UnevaluatedConst<'tcx> { } } +#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] +pub enum ExprKind { + Binop(mir::BinOp), + UnOp(mir::UnOp), + FunctionCall, + Cast(CastKind), +} #[derive(Copy, Clone, Eq, PartialEq, Hash)] #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] -pub enum Expr<'tcx> { - Binop(mir::BinOp, Const<'tcx>, Const<'tcx>), - UnOp(mir::UnOp, Const<'tcx>), - FunctionCall(Const<'tcx>, &'tcx List<Const<'tcx>>), - Cast(CastKind, Const<'tcx>, Ty<'tcx>), +pub struct Expr<'tcx> { + pub kind: ExprKind, + args: ty::GenericArgsRef<'tcx>, +} +impl<'tcx> Expr<'tcx> { + pub fn new_binop( + tcx: TyCtxt<'tcx>, + binop: mir::BinOp, + lhs_ty: Ty<'tcx>, + rhs_ty: Ty<'tcx>, + lhs_ct: Const<'tcx>, + rhs_ct: Const<'tcx>, + ) -> Self { + let args = tcx.mk_args_from_iter::<_, ty::GenericArg<'tcx>>( + [lhs_ty.into(), rhs_ty.into(), lhs_ct.into(), rhs_ct.into()].into_iter(), + ); + + Self { kind: ExprKind::Binop(binop), args } + } + + pub fn binop_args(self) -> (Ty<'tcx>, Ty<'tcx>, Const<'tcx>, Const<'tcx>) { + assert!(matches!(self.kind, ExprKind::Binop(_))); + + match self.args().as_slice() { + [lhs_ty, rhs_ty, lhs_ct, rhs_ct] => ( + lhs_ty.expect_ty(), + rhs_ty.expect_ty(), + lhs_ct.expect_const(), + rhs_ct.expect_const(), + ), + _ => bug!("Invalid args for `Binop` expr {self:?}"), + } + } + + pub fn new_unop(tcx: TyCtxt<'tcx>, unop: mir::UnOp, ty: Ty<'tcx>, ct: Const<'tcx>) -> Self { + let args = + tcx.mk_args_from_iter::<_, ty::GenericArg<'tcx>>([ty.into(), ct.into()].into_iter()); + + Self { kind: ExprKind::UnOp(unop), args } + } + + pub fn unop_args(self) -> (Ty<'tcx>, Const<'tcx>) { + assert!(matches!(self.kind, ExprKind::UnOp(_))); + + match self.args().as_slice() { + [ty, ct] => (ty.expect_ty(), ct.expect_const()), + _ => bug!("Invalid args for `UnOp` expr {self:?}"), + } + } + + pub fn new_call( + tcx: TyCtxt<'tcx>, + func_ty: Ty<'tcx>, + func_expr: Const<'tcx>, + arguments: impl IntoIterator<Item = Const<'tcx>>, + ) -> Self { + let args = tcx.mk_args_from_iter::<_, ty::GenericArg<'tcx>>( + [func_ty.into(), func_expr.into()] + .into_iter() + .chain(arguments.into_iter().map(|ct| ct.into())), + ); + + Self { kind: ExprKind::FunctionCall, args } + } + + pub fn call_args(self) -> (Ty<'tcx>, Const<'tcx>, impl Iterator<Item = Const<'tcx>>) { + assert!(matches!(self.kind, ExprKind::FunctionCall)); + + match self.args().as_slice() { + [func_ty, func, rest @ ..] => ( + func_ty.expect_ty(), + func.expect_const(), + rest.iter().map(|arg| arg.expect_const()), + ), + _ => bug!("Invalid args for `Call` expr {self:?}"), + } + } + + pub fn new_cast( + tcx: TyCtxt<'tcx>, + cast: CastKind, + value_ty: Ty<'tcx>, + value: Const<'tcx>, + to_ty: Ty<'tcx>, + ) -> Self { + let args = tcx.mk_args_from_iter::<_, ty::GenericArg<'tcx>>( + [value_ty.into(), value.into(), to_ty.into()].into_iter(), + ); + + Self { kind: ExprKind::Cast(cast), args } + } + + pub fn cast_args(self) -> (Ty<'tcx>, Const<'tcx>, Ty<'tcx>) { + assert!(matches!(self.kind, ExprKind::Cast(_))); + + match self.args().as_slice() { + [value_ty, value, to_ty] => { + (value_ty.expect_ty(), value.expect_const(), to_ty.expect_ty()) + } + _ => bug!("Invalid args for `Cast` expr {self:?}"), + } + } + + pub fn new(kind: ExprKind, args: ty::GenericArgsRef<'tcx>) -> Self { + Self { kind, args } + } + + pub fn args(self) -> ty::GenericArgsRef<'tcx> { + self.args + } } #[cfg(target_pointer_width = "64")] -rustc_data_structures::static_assert_size!(Expr<'_>, 24); +rustc_data_structures::static_assert_size!(Expr<'_>, 16); diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index 96bc5515a56..efc91357af8 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -79,7 +79,7 @@ impl<'tcx> ValTree<'tcx> { } pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> { - self.try_to_scalar_int().and_then(|s| s.try_to_target_usize(tcx).ok()) + self.try_to_scalar_int().map(|s| s.to_target_usize(tcx)) } /// Get the values inside the ValTree as a slice of bytes. This only works for @@ -100,8 +100,9 @@ impl<'tcx> ValTree<'tcx> { _ => return None, } - Some(tcx.arena.alloc_from_iter( - self.unwrap_branch().into_iter().map(|v| v.unwrap_leaf().try_to_u8().unwrap()), - )) + Some( + tcx.arena + .alloc_from_iter(self.unwrap_branch().into_iter().map(|v| v.unwrap_leaf().to_u8())), + ) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 47f66c64406..65d744239a6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -28,10 +28,10 @@ use crate::traits::solve::{ }; 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, - PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, - Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, Visibility, + self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, GenericParamDefKind, + ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern, PatternKind, + PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, Region, + RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, Visibility, }; use crate::ty::{GenericArg, GenericArgs, GenericArgsRef}; use rustc_ast::{self as ast, attr}; @@ -69,6 +69,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; +use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::TyKind::*; use rustc_type_ir::WithCachedTypeInfo; use rustc_type_ir::{CollectAndApply, Interner, TypeFlags}; @@ -135,9 +136,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type ParamEnv = ty::ParamEnv<'tcx>; type Predicate = Predicate<'tcx>; type Clause = Clause<'tcx>; - type Clauses = ty::Clauses<'tcx>; + fn expand_abstract_consts<T: TypeFoldable<TyCtxt<'tcx>>>(self, t: T) -> T { + self.expand_abstract_consts(t) + } + fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars { self.mk_canonical_var_infos(infos) } @@ -148,6 +152,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.generics_of(def_id) } + type VariancesOf = &'tcx [ty::Variance]; + + fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf { + self.variances_of(def_id) + } + fn type_of(self, def_id: DefId) -> ty::EarlyBinder<'tcx, Ty<'tcx>> { self.type_of(def_id) } @@ -205,7 +215,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.mk_args(args) } - fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> Self::GenericArgs { + fn mk_args_from_iter<I, T>(self, args: I) -> T::Output + where + I: Iterator<Item = T>, + T: CollectAndApply<Self::GenericArg, Self::GenericArgs>, + { self.mk_args_from_iter(args) } @@ -224,6 +238,14 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.arena.alloc(step) } + fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output + where + I: Iterator<Item = T>, + T: CollectAndApply<Self::Ty, Self::Tys>, + { + self.mk_type_list_from_iter(args) + } + fn parent(self, def_id: Self::DefId) -> Self::DefId { self.parent(def_id) } @@ -231,6 +253,12 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn recursion_limit(self) -> usize { self.recursion_limit().0 } + + type Features = &'tcx rustc_feature::Features; + + fn features(self) -> Self::Features { + self.features() + } } impl<'tcx> rustc_type_ir::inherent::Abi<TyCtxt<'tcx>> for abi::Abi { @@ -249,6 +277,12 @@ impl<'tcx> rustc_type_ir::inherent::Safety<TyCtxt<'tcx>> for hir::Safety { } } +impl<'tcx> rustc_type_ir::inherent::Features<TyCtxt<'tcx>> for &'tcx rustc_feature::Features { + fn generic_const_exprs(self) -> bool { + self.generic_const_exprs + } +} + type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>; pub struct CtxtInterners<'tcx> { @@ -268,7 +302,7 @@ pub struct CtxtInterners<'tcx> { clauses: InternedSet<'tcx, ListWithCachedTypeInfo<Clause<'tcx>>>, projs: InternedSet<'tcx, List<ProjectionKind>>, place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>, - const_: InternedSet<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>, + const_: InternedSet<'tcx, WithCachedTypeInfo<ty::ConstKind<'tcx>>>, pat: InternedSet<'tcx, PatternKind<'tcx>>, const_allocation: InternedSet<'tcx, Allocation>, bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>, @@ -338,18 +372,18 @@ impl<'tcx> CtxtInterners<'tcx> { #[inline(never)] fn intern_const( &self, - data: ty::ConstData<'tcx>, + kind: ty::ConstKind<'tcx>, sess: &Session, untracked: &Untracked, ) -> Const<'tcx> { Const(Interned::new_unchecked( self.const_ - .intern(data, |data: ConstData<'_>| { - let flags = super::flags::FlagComputation::for_const(&data.kind, data.ty); - let stable_hash = self.stable_hash(&flags, sess, untracked, &data); + .intern(kind, |kind: ty::ConstKind<'_>| { + let flags = super::flags::FlagComputation::for_const_kind(&kind); + let stable_hash = self.stable_hash(&flags, sess, untracked, &kind); InternedInSet(self.arena.alloc(WithCachedTypeInfo { - internee: data, + internee: kind, stable_hash, flags: flags.flags, outer_exclusive_binder: flags.outer_exclusive_binder, @@ -601,18 +635,15 @@ impl<'tcx> CommonConsts<'tcx> { }; CommonConsts { - unit: mk_const(ty::ConstData { - kind: ty::ConstKind::Value(ty::ValTree::zst()), - ty: types.unit, - }), - true_: mk_const(ty::ConstData { - kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::TRUE)), - ty: types.bool, - }), - false_: mk_const(ty::ConstData { - kind: ty::ConstKind::Value(ty::ValTree::Leaf(ty::ScalarInt::FALSE)), - ty: types.bool, - }), + unit: mk_const(ty::ConstKind::Value(types.unit, ty::ValTree::zst())), + true_: mk_const(ty::ConstKind::Value( + types.bool, + ty::ValTree::Leaf(ty::ScalarInt::TRUE), + )), + false_: mk_const(ty::ConstKind::Value( + types.bool, + ty::ValTree::Leaf(ty::ScalarInt::FALSE), + )), } } } @@ -743,7 +774,6 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> { 1, ), bodies, - has_inline_consts: false, }))); self.feed_owner_id().hir_attrs(attrs); } @@ -1619,7 +1649,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx { iter::once(LOCAL_CRATE) - .chain(self.used_crates(()).iter().copied()) + .chain(self.crates(()).iter().copied()) .flat_map(move |cnum| self.traits(cnum).iter().copied()) } @@ -2225,9 +2255,9 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn mk_ct_from_kind(self, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> { + pub fn mk_ct_from_kind(self, kind: ty::ConstKind<'tcx>) -> Const<'tcx> { self.interners.intern_const( - ty::ConstData { kind, ty }, + kind, self.sess, // This is only used to create a stable hashing context. &self.untracked, @@ -2252,14 +2282,10 @@ impl<'tcx> TyCtxt<'tcx> { ty::Region::new_early_param(self, param.to_early_bound_region_data()).into() } GenericParamDefKind::Type { .. } => Ty::new_param(self, param.index, param.name).into(), - GenericParamDefKind::Const { .. } => ty::Const::new_param( - self, - ParamConst { index: param.index, name: param.name }, - self.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), - ) - .into(), + GenericParamDefKind::Const { .. } => { + ty::Const::new_param(self, ParamConst { index: param.index, name: param.name }) + .into() + } } } diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 99d703be873..32dc9fa5fc6 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -1,91 +1,26 @@ use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, PrettyPrinter}; -use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt}; +use crate::ty::{self, Ty, TyCtxt}; + use rustc_errors::pluralize; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind}; -use rustc_hir::def_id::DefId; -use rustc_macros::{TypeFoldable, TypeVisitable}; -use rustc_span::symbol::Symbol; -use rustc_target::spec::abi; +use rustc_macros::extension; +pub use rustc_type_ir::error::ExpectedFound; + use std::borrow::Cow; use std::hash::{DefaultHasher, Hash, Hasher}; use std::path::PathBuf; -#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)] -pub struct ExpectedFound<T> { - pub expected: T, - pub found: T, -} - -impl<T> ExpectedFound<T> { - pub fn new(a_is_expected: bool, a: T, b: T) -> Self { - if a_is_expected { - ExpectedFound { expected: a, found: b } - } else { - ExpectedFound { expected: b, found: a } - } - } -} - -// Data structures used in type unification -#[derive(Copy, Clone, Debug, TypeVisitable, PartialEq, Eq)] -#[rustc_pass_by_value] -pub enum TypeError<'tcx> { - Mismatch, - ConstnessMismatch(ExpectedFound<ty::BoundConstness>), - PolarityMismatch(ExpectedFound<ty::PredicatePolarity>), - SafetyMismatch(ExpectedFound<hir::Safety>), - AbiMismatch(ExpectedFound<abi::Abi>), - Mutability, - ArgumentMutability(usize), - TupleSize(ExpectedFound<usize>), - FixedArraySize(ExpectedFound<u64>), - ArgCount, - FieldMisMatch(Symbol, Symbol), - - RegionsDoesNotOutlive(Region<'tcx>, Region<'tcx>), - RegionsInsufficientlyPolymorphic(BoundRegionKind, Region<'tcx>), - RegionsPlaceholderMismatch, - - Sorts(ExpectedFound<Ty<'tcx>>), - ArgumentSorts(ExpectedFound<Ty<'tcx>>, usize), - IntMismatch(ExpectedFound<ty::IntVarValue>), - FloatMismatch(ExpectedFound<ty::FloatTy>), - Traits(ExpectedFound<DefId>), - VariadicMismatch(ExpectedFound<bool>), - - /// Instantiating a type variable with the given type would have - /// created a cycle (because it appears somewhere within that - /// type). - CyclicTy(Ty<'tcx>), - CyclicConst(ty::Const<'tcx>), - ProjectionMismatched(ExpectedFound<DefId>), - ExistentialMismatch(ExpectedFound<&'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>>), - ConstMismatch(ExpectedFound<ty::Const<'tcx>>), - - IntrinsicCast, - /// Safe `#[target_feature]` functions are not assignable to safe function pointers. - TargetFeatureCast(DefId), -} - -impl TypeError<'_> { - pub fn involves_regions(self) -> bool { - match self { - TypeError::RegionsDoesNotOutlive(_, _) - | TypeError::RegionsInsufficientlyPolymorphic(_, _) - | TypeError::RegionsPlaceholderMismatch => true, - _ => false, - } - } -} +pub type TypeError<'tcx> = rustc_type_ir::error::TypeError<TyCtxt<'tcx>>; -/// Explains the source of a type err in a short, human readable way. This is meant to be placed -/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()` -/// afterwards to present additional details, particularly when it comes to lifetime-related -/// errors. +/// Explains the source of a type err in a short, human readable way. +/// This is meant to be placed in parentheses after some larger message. +/// You should also invoke `note_and_explain_type_err()` afterwards +/// to present additional details, particularly when it comes to lifetime- +/// related errors. +#[extension(pub trait TypeErrorToStringExt<'tcx>)] impl<'tcx> TypeError<'tcx> { - pub fn to_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str> { - use self::TypeError::*; + fn to_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str> { fn report_maybe_different(expected: &str, found: &str) -> String { // A naive approach to making sure that we're not reporting silly errors such as: // (expected closure, found closure). @@ -97,24 +32,26 @@ impl<'tcx> TypeError<'tcx> { } match self { - CyclicTy(_) => "cyclic type of infinite size".into(), - CyclicConst(_) => "encountered a self-referencing constant".into(), - Mismatch => "types differ".into(), - ConstnessMismatch(values) => { + TypeError::CyclicTy(_) => "cyclic type of infinite size".into(), + TypeError::CyclicConst(_) => "encountered a self-referencing constant".into(), + TypeError::Mismatch => "types differ".into(), + TypeError::ConstnessMismatch(values) => { format!("expected {} bound, found {} bound", values.expected, values.found).into() } - PolarityMismatch(values) => { + TypeError::PolarityMismatch(values) => { format!("expected {} polarity, found {} polarity", values.expected, values.found) .into() } - SafetyMismatch(values) => { + TypeError::SafetyMismatch(values) => { format!("expected {} fn, found {} fn", values.expected, values.found).into() } - AbiMismatch(values) => { + TypeError::AbiMismatch(values) => { format!("expected {} fn, found {} fn", values.expected, values.found).into() } - ArgumentMutability(_) | Mutability => "types differ in mutability".into(), - TupleSize(values) => format!( + TypeError::ArgumentMutability(_) | TypeError::Mutability => { + "types differ in mutability".into() + } + TypeError::TupleSize(values) => format!( "expected a tuple with {} element{}, found one with {} element{}", values.expected, pluralize!(values.expected), @@ -122,7 +59,7 @@ impl<'tcx> TypeError<'tcx> { pluralize!(values.found) ) .into(), - FixedArraySize(values) => format!( + TypeError::FixedArraySize(values) => format!( "expected an array with a fixed size of {} element{}, found one with {} element{}", values.expected, pluralize!(values.expected), @@ -130,20 +67,21 @@ impl<'tcx> TypeError<'tcx> { pluralize!(values.found) ) .into(), - ArgCount => "incorrect number of function parameters".into(), - FieldMisMatch(adt, field) => format!("field type mismatch: {adt}.{field}").into(), - RegionsDoesNotOutlive(..) => "lifetime mismatch".into(), + TypeError::ArgCount => "incorrect number of function parameters".into(), + TypeError::RegionsDoesNotOutlive(..) => "lifetime mismatch".into(), // Actually naming the region here is a bit confusing because context is lacking - RegionsInsufficientlyPolymorphic(..) => { + TypeError::RegionsInsufficientlyPolymorphic(..) => { + "one type is more general than the other".into() + } + TypeError::RegionsPlaceholderMismatch => { "one type is more general than the other".into() } - RegionsPlaceholderMismatch => "one type is more general than the other".into(), - ArgumentSorts(values, _) | Sorts(values) => { + TypeError::ArgumentSorts(values, _) | TypeError::Sorts(values) => { let expected = values.expected.sort_string(tcx); let found = values.found.sort_string(tcx); report_maybe_different(&expected, &found).into() } - Traits(values) => { + TypeError::Traits(values) => { let (mut expected, mut found) = with_forced_trimmed_paths!(( tcx.def_path_str(values.expected), tcx.def_path_str(values.found), @@ -155,77 +93,34 @@ impl<'tcx> TypeError<'tcx> { report_maybe_different(&format!("trait `{expected}`"), &format!("trait `{found}`")) .into() } - IntMismatch(ref values) => { - let expected = match values.expected { - ty::IntVarValue::IntType(ty) => ty.name_str(), - ty::IntVarValue::UintType(ty) => ty.name_str(), - }; - let found = match values.found { - ty::IntVarValue::IntType(ty) => ty.name_str(), - ty::IntVarValue::UintType(ty) => ty.name_str(), - }; - format!("expected `{expected}`, found `{found}`").into() - } - FloatMismatch(ref values) => format!( - "expected `{}`, found `{}`", - values.expected.name_str(), - values.found.name_str() - ) - .into(), - VariadicMismatch(ref values) => format!( + TypeError::VariadicMismatch(ref values) => format!( "expected {} fn, found {} function", if values.expected { "variadic" } else { "non-variadic" }, if values.found { "variadic" } else { "non-variadic" } ) .into(), - ProjectionMismatched(ref values) => format!( + TypeError::ProjectionMismatched(ref values) => format!( "expected `{}`, found `{}`", tcx.def_path_str(values.expected), tcx.def_path_str(values.found) ) .into(), - ExistentialMismatch(ref values) => report_maybe_different( + TypeError::ExistentialMismatch(ref values) => report_maybe_different( &format!("trait `{}`", values.expected), &format!("trait `{}`", values.found), ) .into(), - ConstMismatch(ref values) => { + TypeError::ConstMismatch(ref values) => { format!("expected `{}`, found `{}`", values.expected, values.found).into() } - IntrinsicCast => "cannot coerce intrinsics to function pointers".into(), - TargetFeatureCast(_) => { + TypeError::IntrinsicCast => "cannot coerce intrinsics to function pointers".into(), + TypeError::TargetFeatureCast(_) => { "cannot coerce functions with `#[target_feature]` to safe function pointers".into() } } } } -impl<'tcx> TypeError<'tcx> { - pub fn must_include_note(self) -> bool { - use self::TypeError::*; - match self { - CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | ConstnessMismatch(_) - | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_) - | ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_) - | VariadicMismatch(_) | TargetFeatureCast(_) => false, - - Mutability - | ArgumentMutability(_) - | TupleSize(_) - | ArgCount - | FieldMisMatch(..) - | RegionsDoesNotOutlive(..) - | RegionsInsufficientlyPolymorphic(..) - | RegionsPlaceholderMismatch - | Traits(_) - | ProjectionMismatched(_) - | ExistentialMismatch(_) - | ConstMismatch(_) - | IntrinsicCast => true, - } - } -} - impl<'tcx> Ty<'tcx> { pub fn sort_string(self, tcx: TyCtxt<'tcx>) -> Cow<'static, str> { match *self.kind() { diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 7508f0080cc..923667e609b 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -337,7 +337,7 @@ impl DeepRejectCtxt { | ty::ConstKind::Error(_) => { return true; } - ty::ConstKind::Value(impl_val) => impl_val, + ty::ConstKind::Value(_, impl_val) => impl_val, ty::ConstKind::Infer(_) | ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => { bug!("unexpected impl arg: {:?}", impl_ct) } @@ -357,7 +357,7 @@ impl DeepRejectCtxt { ty::ConstKind::Expr(_) | ty::ConstKind::Unevaluated(_) | ty::ConstKind::Error(_) => { true } - ty::ConstKind::Value(obl_val) => obl_val == impl_val, + ty::ConstKind::Value(_, obl_val) => obl_val == impl_val, ty::ConstKind::Infer(_) => true, diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 4de7d532c96..21c115c2c96 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -28,10 +28,9 @@ impl FlagComputation { result } - pub fn for_const(c: &ty::ConstKind<'_>, t: Ty<'_>) -> FlagComputation { + pub fn for_const_kind(kind: &ty::ConstKind<'_>) -> FlagComputation { let mut result = FlagComputation::new(); - result.add_const_kind(c); - result.add_ty(t); + result.add_const_kind(kind); result } @@ -373,27 +372,8 @@ impl FlagComputation { self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER); self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); } - ty::ConstKind::Value(_) => {} - ty::ConstKind::Expr(e) => { - use ty::Expr; - match e { - Expr::Binop(_, l, r) => { - self.add_const(l); - self.add_const(r); - } - Expr::UnOp(_, v) => self.add_const(v), - Expr::FunctionCall(f, args) => { - self.add_const(f); - for arg in args { - self.add_const(arg); - } - } - Expr::Cast(_, c, t) => { - self.add_ty(t); - self.add_const(c); - } - } - } + ty::ConstKind::Value(ty, _) => self.add_ty(ty), + ty::ConstKind::Expr(e) => self.add_args(e.args()), ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), } } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index b5b36cbd1ba..9b5b1430c27 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -134,13 +134,13 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for RegionFolder<'a, 'tcx> { pub trait BoundVarReplacerDelegate<'tcx> { fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx>; fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx>; - fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx>; + fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx>; } pub struct FnMutDelegate<'a, 'tcx> { pub regions: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), pub types: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a), - pub consts: &'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a), + pub consts: &'a mut (dyn FnMut(ty::BoundVar) -> ty::Const<'tcx> + 'a), } impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> { @@ -150,8 +150,8 @@ impl<'a, 'tcx> BoundVarReplacerDelegate<'tcx> for FnMutDelegate<'a, 'tcx> { fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> { (self.types)(bt) } - fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> { - (self.consts)(bv, ty) + fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> { + (self.consts)(bv) } } @@ -224,7 +224,7 @@ where fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { match ct.kind() { ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => { - let ct = self.delegate.replace_const(bound_const, ct.ty()); + let ct = self.delegate.replace_const(bound_const); debug_assert!(!ct.has_vars_bound_above(ty::INNERMOST)); ty::fold::shift_vars(self.tcx, ct, self.current_index.as_u32()) } @@ -282,7 +282,7 @@ impl<'tcx> TyCtxt<'tcx> { let delegate = FnMutDelegate { regions: &mut replace_regions, types: &mut |b| bug!("unexpected bound ty in binder: {b:?}"), - consts: &mut |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"), + consts: &mut |b| bug!("unexpected bound ct in binder: {b:?}"), }; let mut replacer = BoundVarReplacer::new(self, delegate); value.fold_with(&mut replacer) @@ -353,9 +353,7 @@ impl<'tcx> TyCtxt<'tcx> { ty::BoundTy { var: shift_bv(t.var), kind: t.kind }, ) }, - consts: &mut |c, ty: Ty<'tcx>| { - ty::Const::new_bound(self, ty::INNERMOST, shift_bv(c), ty) - }, + consts: &mut |c| ty::Const::new_bound(self, ty::INNERMOST, shift_bv(c)), }, ) } @@ -398,12 +396,12 @@ impl<'tcx> TyCtxt<'tcx> { .expect_ty(); Ty::new_bound(self.tcx, ty::INNERMOST, BoundTy { var, kind }) } - fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> { + fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx> { let entry = self.map.entry(bv); let index = entry.index(); let var = ty::BoundVar::from_usize(index); let () = entry.or_insert_with(|| ty::BoundVariableKind::Const).expect_const(); - ty::Const::new_bound(self.tcx, ty::INNERMOST, var, ty) + ty::Const::new_bound(self.tcx, ty::INNERMOST, var) } } diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index c3ab755175d..7fff3d01324 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -228,7 +228,7 @@ impl<'tcx> GenericArg<'tcx> { ptr.cast::<WithCachedTypeInfo<ty::TyKind<'tcx>>>().as_ref(), ))), CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked( - ptr.cast::<WithCachedTypeInfo<ty::ConstData<'tcx>>>().as_ref(), + ptr.cast::<WithCachedTypeInfo<ty::ConstKind<'tcx>>>().as_ref(), ))), _ => intrinsics::unreachable(), } @@ -454,11 +454,11 @@ impl<'tcx> GenericArgs<'tcx> { def_id: DefId, original_args: &[GenericArg<'tcx>], ) -> GenericArgsRef<'tcx> { - ty::GenericArgs::for_item(tcx, def_id, |def, args| { + ty::GenericArgs::for_item(tcx, def_id, |def, _| { if let Some(arg) = original_args.get(def.index as usize) { *arg } else { - def.to_error(tcx, args) + def.to_error(tcx) } }) } diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 89ba8cd2ad4..185dbe44735 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -100,19 +100,11 @@ impl GenericParamDef { } } - pub fn to_error<'tcx>( - &self, - tcx: TyCtxt<'tcx>, - preceding_args: &[ty::GenericArg<'tcx>], - ) -> ty::GenericArg<'tcx> { + pub fn to_error<'tcx>(&self, tcx: TyCtxt<'tcx>) -> ty::GenericArg<'tcx> { match &self.kind { ty::GenericParamDefKind::Lifetime => ty::Region::new_error_misc(tcx).into(), ty::GenericParamDefKind::Type { .. } => Ty::new_misc_error(tcx).into(), - ty::GenericParamDefKind::Const { .. } => ty::Const::new_misc_error( - tcx, - tcx.type_of(self.def_id).instantiate(tcx, preceding_args), - ) - .into(), + ty::GenericParamDefKind::Const { .. } => ty::Const::new_misc_error(tcx).into(), } } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index a2df90b2c0f..56945bf6be4 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -385,9 +385,7 @@ impl<'tcx> SizeSkeleton<'tcx> { ), } } - ty::Array(inner, len) - if len.ty() == tcx.types.usize && tcx.features().transmute_generic_consts => - { + ty::Array(inner, len) if tcx.features().transmute_generic_consts => { let len_eval = len.try_eval_target_usize(tcx, param_env); if len_eval == Some(0) { return Ok(SizeSkeleton::Known(Size::from_bytes(0))); @@ -1353,3 +1351,37 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { } impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {} + +impl<'tcx> TyCtxt<'tcx> { + pub fn offset_of_subfield<I>( + self, + param_env: ty::ParamEnv<'tcx>, + mut layout: TyAndLayout<'tcx>, + indices: I, + ) -> Size + where + I: Iterator<Item = (VariantIdx, FieldIdx)>, + { + let cx = LayoutCx { tcx: self, param_env }; + let mut offset = Size::ZERO; + + for (variant, field) in indices { + layout = layout.for_variant(&cx, variant); + let index = field.index(); + offset += layout.fields.offset(index); + layout = layout.field(&cx, index); + if !layout.is_sized() { + // If it is not sized, then the tail must still have at least a known static alignment. + let tail = self.struct_tail_erasing_lifetimes(layout.ty, param_env); + if !matches!(tail.kind(), ty::Slice(..)) { + bug!( + "offset of not-statically-aligned field (type {:?}) cannot be computed statically", + layout.ty + ); + } + } + } + + offset + } +} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 2643ce976de..7ff1b799822 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -60,6 +60,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{ExpnId, ExpnKind, Span}; use rustc_target::abi::{Align, FieldIdx, Integer, IntegerType, VariantIdx}; pub use rustc_target::abi::{ReprFlags, ReprOptions}; +pub use rustc_type_ir::relate::VarianceDiagInfo; pub use rustc_type_ir::{DebugWithInfcx, InferCtxtLike, WithInfcx}; use tracing::{debug, instrument}; pub use vtable::*; @@ -87,7 +88,7 @@ pub use self::closure::{ CAPTURE_STRUCT_LOCAL, }; pub use self::consts::{ - Const, ConstData, ConstInt, ConstKind, Expr, ScalarInt, UnevaluatedConst, ValTree, + Const, ConstInt, ConstKind, Expr, ExprKind, ScalarInt, UnevaluatedConst, ValTree, }; pub use self::context::{ tls, CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, @@ -114,7 +115,7 @@ pub use self::rvalue_scopes::RvalueScopes; pub use self::sty::{ AliasTy, Article, Binder, BoundTy, BoundTyKind, BoundVariableKind, CanonicalPolyFnSig, CoroutineArgsExt, EarlyBinder, FnSig, InlineConstArgs, InlineConstArgsParts, ParamConst, - ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, VarianceDiagInfo, + ParamTy, PolyFnSig, TyKind, TypeAndMut, UpvarArgs, }; pub use self::trait_def::TraitDef; pub use self::typeck_results::{ @@ -122,7 +123,6 @@ pub use self::typeck_results::{ TypeckResults, UserType, UserTypeAnnotationIndex, }; -pub mod _match; pub mod abstract_const; pub mod adjustment; pub mod cast; @@ -313,38 +313,6 @@ impl Visibility { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] -pub enum BoundConstness { - /// `Type: Trait` - NotConst, - /// `Type: const Trait` - Const, - /// `Type: ~const Trait` - /// - /// Requires resolving to const only when we are in a const context. - ConstIfConst, -} - -impl BoundConstness { - pub fn as_str(self) -> &'static str { - match self { - Self::NotConst => "", - Self::Const => "const", - Self::ConstIfConst => "~const", - } - } -} - -impl fmt::Display for BoundConstness { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::NotConst => f.write_str("normal"), - Self::Const => f.write_str("const"), - Self::ConstIfConst => f.write_str("~const"), - } - } -} - #[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)] #[derive(TypeFoldable, TypeVisitable)] pub struct ClosureSizeProfileData<'tcx> { @@ -617,21 +585,29 @@ impl<'tcx> Term<'tcx> { ptr.cast::<WithCachedTypeInfo<ty::TyKind<'tcx>>>().as_ref(), ))), CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked( - ptr.cast::<WithCachedTypeInfo<ty::ConstData<'tcx>>>().as_ref(), + ptr.cast::<WithCachedTypeInfo<ty::ConstKind<'tcx>>>().as_ref(), ))), _ => core::intrinsics::unreachable(), } } } - pub fn ty(&self) -> Option<Ty<'tcx>> { + pub fn as_type(&self) -> Option<Ty<'tcx>> { if let TermKind::Ty(ty) = self.unpack() { Some(ty) } else { None } } - pub fn ct(&self) -> Option<Const<'tcx>> { + pub fn expect_type(&self) -> Ty<'tcx> { + self.as_type().expect("expected a type, but found a const") + } + + pub fn as_const(&self) -> Option<Const<'tcx>> { if let TermKind::Const(c) = self.unpack() { Some(c) } else { None } } + pub fn expect_const(&self) -> Const<'tcx> { + self.as_const().expect("expected a const, but found a type") + } + pub fn into_arg(self) -> GenericArg<'tcx> { match self.unpack() { TermKind::Ty(ty) => ty.into(), @@ -926,6 +902,30 @@ pub struct Placeholder<T> { pub universe: UniverseIndex, pub bound: T, } +impl Placeholder<BoundVar> { + pub fn find_const_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> { + let mut candidates = env.caller_bounds().iter().filter_map(|clause| { + // `ConstArgHasType` are never desugared to be higher ranked. + match clause.kind().skip_binder() { + ty::ClauseKind::ConstArgHasType(placeholder_ct, ty) => { + assert!(!(placeholder_ct, ty).has_escaping_bound_vars()); + + match placeholder_ct.kind() { + ty::ConstKind::Placeholder(placeholder_ct) if placeholder_ct == self => { + Some(ty) + } + _ => None, + } + } + _ => None, + } + }); + + let ty = candidates.next().unwrap(); + assert!(candidates.next().is_none()); + ty + } +} pub type PlaceholderRegion = Placeholder<BoundRegion>; diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index bbcbcdce1b2..52902aadd7c 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -216,7 +216,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> { }) .emit_unless(self.ignore_errors); - ty::Const::new_error(self.tcx, guar, ct.ty()) + ty::Const::new_error(self.tcx, guar) } } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 8fb4367d3b5..662eafd0ccb 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1077,7 +1077,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } p!(")"); - if let Some(ty) = return_ty.skip_binder().ty() { + if let Some(ty) = return_ty.skip_binder().as_type() { if !ty.is_unit() { p!(" -> ", print(return_ty)); } @@ -1144,7 +1144,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { for (assoc_item_def_id, term) in assoc_items { // Skip printing `<{coroutine@} as Coroutine<_>>::Return` from async blocks, // unless we can find out what coroutine return type it comes from. - let term = if let Some(ty) = term.skip_binder().ty() + let term = if let Some(ty) = term.skip_binder().as_type() && let ty::Alias(ty::Projection, proj) = ty.kind() && let Some(assoc) = tcx.opt_associated_item(proj.def_id) && assoc.trait_container(tcx) == tcx.lang_items().coroutine_trait() @@ -1322,7 +1322,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { p!(pretty_fn_sig( tys, false, - proj.skip_binder().term.ty().expect("Return type was a const") + proj.skip_binder().term.as_type().expect("Return type was a const") )); resugared = true; } @@ -1459,23 +1459,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { return Ok(()); } - macro_rules! print_underscore { - () => {{ - if print_ty { - self.typed_value( - |this| { - write!(this, "_")?; - Ok(()) - }, - |this| this.print_type(ct.ty()), - ": ", - )?; - } else { - write!(self, "_")?; - } - }}; - } - match ct.kind() { ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => { match self.tcx().def_kind(def) { @@ -1508,11 +1491,11 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::InferConst::Var(ct_vid) if let Some(name) = self.const_infer_name(ct_vid) => { p!(write("{}", name)) } - _ => print_underscore!(), + _ => write!(self, "_")?, }, ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)), - ty::ConstKind::Value(value) => { - return self.pretty_print_const_valtree(value, ct.ty(), print_ty); + ty::ConstKind::Value(ty, value) => { + return self.pretty_print_const_valtree(value, ty, print_ty); } ty::ConstKind::Bound(debruijn, bound_var) => { @@ -1533,8 +1516,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { print_ty: bool, ) -> Result<(), PrintError> { define_scoped_cx!(self); - match expr { - Expr::Binop(op, c1, c2) => { + match expr.kind { + ty::ExprKind::Binop(op) => { + let (_, _, c1, c2) = expr.binop_args(); + let precedence = |binop: rustc_middle::mir::BinOp| { use rustc_ast::util::parser::AssocOp; AssocOp::from_ast_binop(binop.to_hir_binop().into()).precedence() @@ -1543,22 +1528,26 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let formatted_op = op.to_hir_binop().as_str(); let (lhs_parenthesized, rhs_parenthesized) = match (c1.kind(), c2.kind()) { ( - ty::ConstKind::Expr(Expr::Binop(lhs_op, _, _)), - ty::ConstKind::Expr(Expr::Binop(rhs_op, _, _)), + ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(lhs_op), .. }), + ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(rhs_op), .. }), ) => (precedence(lhs_op) < op_precedence, precedence(rhs_op) < op_precedence), - (ty::ConstKind::Expr(Expr::Binop(lhs_op, ..)), ty::ConstKind::Expr(_)) => { - (precedence(lhs_op) < op_precedence, true) - } - (ty::ConstKind::Expr(_), ty::ConstKind::Expr(Expr::Binop(rhs_op, ..))) => { - (true, precedence(rhs_op) < op_precedence) - } + ( + ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(lhs_op), .. }), + ty::ConstKind::Expr(_), + ) => (precedence(lhs_op) < op_precedence, true), + ( + ty::ConstKind::Expr(_), + ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(rhs_op), .. }), + ) => (true, precedence(rhs_op) < op_precedence), (ty::ConstKind::Expr(_), ty::ConstKind::Expr(_)) => (true, true), - (ty::ConstKind::Expr(Expr::Binop(lhs_op, ..)), _) => { - (precedence(lhs_op) < op_precedence, false) - } - (_, ty::ConstKind::Expr(Expr::Binop(rhs_op, ..))) => { - (false, precedence(rhs_op) < op_precedence) - } + ( + ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(lhs_op), .. }), + _, + ) => (precedence(lhs_op) < op_precedence, false), + ( + _, + ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::Binop(rhs_op), .. }), + ) => (false, precedence(rhs_op) < op_precedence), (ty::ConstKind::Expr(_), _) => (true, false), (_, ty::ConstKind::Expr(_)) => (false, true), _ => (false, false), @@ -1574,7 +1563,9 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { rhs_parenthesized, )?; } - Expr::UnOp(op, ct) => { + ty::ExprKind::UnOp(op) => { + let (_, ct) = expr.unop_args(); + use rustc_middle::mir::UnOp; let formatted_op = match op { UnOp::Not => "!", @@ -1583,7 +1574,9 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { }; let parenthesized = match ct.kind() { _ if op == UnOp::PtrMetadata => true, - ty::ConstKind::Expr(Expr::UnOp(c_op, ..)) => c_op != op, + ty::ConstKind::Expr(ty::Expr { kind: ty::ExprKind::UnOp(c_op), .. }) => { + c_op != op + } ty::ConstKind::Expr(_) => true, _ => false, }; @@ -1593,61 +1586,37 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { parenthesized, )? } - Expr::FunctionCall(fn_def, fn_args) => { - use ty::TyKind; - match fn_def.ty().kind() { - TyKind::FnDef(def_id, gen_args) => { - p!(print_value_path(*def_id, gen_args), "("); - if print_ty { - let tcx = self.tcx(); - let sig = tcx.fn_sig(def_id).instantiate(tcx, gen_args).skip_binder(); - - let mut args_with_ty = fn_args.iter().map(|ct| (ct, ct.ty())); - let output_ty = sig.output(); - - if let Some((ct, ty)) = args_with_ty.next() { - self.typed_value( - |this| this.pretty_print_const(ct, print_ty), - |this| this.pretty_print_type(ty), - ": ", - )?; - for (ct, ty) in args_with_ty { - p!(", "); - self.typed_value( - |this| this.pretty_print_const(ct, print_ty), - |this| this.pretty_print_type(ty), - ": ", - )?; - } - } - p!(write(") -> {output_ty}")); - } else { - p!(comma_sep(fn_args.iter()), ")"); - } - } - _ => bug!("unexpected type of fn def"), - } + ty::ExprKind::FunctionCall => { + let (_, fn_def, fn_args) = expr.call_args(); + + write!(self, "(")?; + self.pretty_print_const(fn_def, print_ty)?; + p!(")(", comma_sep(fn_args), ")"); } - Expr::Cast(kind, ct, ty) => { + ty::ExprKind::Cast(kind) => { + let (_, value, to_ty) = expr.cast_args(); + use ty::abstract_const::CastKind; if kind == CastKind::As || (kind == CastKind::Use && self.should_print_verbose()) { - let parenthesized = match ct.kind() { - ty::ConstKind::Expr(Expr::Cast(_, _, _)) => false, + let parenthesized = match value.kind() { + ty::ConstKind::Expr(ty::Expr { + kind: ty::ExprKind::Cast { .. }, .. + }) => false, ty::ConstKind::Expr(_) => true, _ => false, }; self.maybe_parenthesized( |this| { this.typed_value( - |this| this.pretty_print_const(ct, print_ty), - |this| this.pretty_print_type(ty), + |this| this.pretty_print_const(value, print_ty), + |this| this.pretty_print_type(to_ty), " as ", ) }, parenthesized, )?; } else { - self.pretty_print_const(ct, print_ty)? + self.pretty_print_const(value, print_ty)? } } } @@ -1680,10 +1649,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::Ref(_, inner, _) => { if let ty::Array(elem, len) = inner.kind() { if let ty::Uint(ty::UintTy::U8) = elem.kind() { - if let ty::ConstKind::Value(ty::ValTree::Leaf(int)) = len.kind() { + if let ty::ConstKind::Value(_, ty::ValTree::Leaf(int)) = len.kind() { match self.tcx().try_get_global_alloc(prov.alloc_id()) { Some(GlobalAlloc::Memory(alloc)) => { - let len = int.assert_bits(self.tcx().data_layout.pointer_size); + let len = int.to_bits(self.tcx().data_layout.pointer_size); let range = AllocRange { start: offset, size: Size::from_bytes(len) }; if let Ok(byte_str) = @@ -1761,7 +1730,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } // Pointer types ty::Ref(..) | ty::RawPtr(_, _) | ty::FnPtr(_) => { - let data = int.assert_bits(self.tcx().data_layout.pointer_size); + let data = int.to_bits(self.tcx().data_layout.pointer_size); self.typed_value( |this| { write!(this, "0x{data:x}")?; @@ -3263,7 +3232,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N let queue = &mut Vec::new(); let mut seen_defs: DefIdSet = Default::default(); - for &cnum in tcx.crates_including_speculative(()).iter() { + for &cnum in tcx.crates(()).iter() { let def_id = cnum.as_def_id(); // Ignore crates that are not direct dependencies. diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index b4179858890..b169d672a84 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -1,383 +1,54 @@ -//! Generalized type relating mechanism. -//! -//! A type relation `R` relates a pair of values `(A, B)`. `A and B` are usually -//! types or regions but can be other things. Examples of type relations are -//! subtyping, type equality, etc. +use std::iter; -use crate::ty::error::{ExpectedFound, TypeError}; -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_id::DefId; -use rustc_macros::TypeVisitable; use rustc_target::spec::abi; -use std::iter; -use tracing::{debug, instrument}; - -use super::Pattern; - -pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>; - -pub trait TypeRelation<'tcx>: Sized { - fn tcx(&self) -> TyCtxt<'tcx>; - - /// Returns a static string we can use for printouts. - fn tag(&self) -> &'static str; - - /// Generic relation routine suitable for most anything. - fn relate<T: Relate<'tcx>>(&mut self, a: T, b: T) -> RelateResult<'tcx, T> { - Relate::relate(self, a, b) - } - - /// Relate the two args for the given item. The default - /// is to look up the variance for the item and proceed - /// accordingly. - fn relate_item_args( - &mut self, - item_def_id: DefId, - a_arg: GenericArgsRef<'tcx>, - b_arg: GenericArgsRef<'tcx>, - ) -> RelateResult<'tcx, GenericArgsRef<'tcx>> { - debug!( - "relate_item_args(item_def_id={:?}, a_arg={:?}, b_arg={:?})", - item_def_id, a_arg, b_arg - ); - - let tcx = self.tcx(); - let opt_variances = tcx.variances_of(item_def_id); - relate_args_with_variances(self, item_def_id, opt_variances, a_arg, b_arg, true) - } - - /// Switch variance for the purpose of relating `a` and `b`. - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - variance: ty::Variance, - info: ty::VarianceDiagInfo<'tcx>, - a: T, - b: T, - ) -> RelateResult<'tcx, T>; - - // Overridable relations. You shouldn't typically call these - // directly, instead call `relate()`, which in turn calls - // these. This is both more uniform but also allows us to add - // additional hooks for other types in the future if needed - // without making older code, which called `relate`, obsolete. - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>>; - - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>>; - - fn consts( - &mut self, - a: ty::Const<'tcx>, - b: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>>; - - fn binders<T>( - &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate<'tcx>; -} - -pub trait Relate<'tcx>: TypeFoldable<TyCtxt<'tcx>> + PartialEq + Copy { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: Self, - b: Self, - ) -> RelateResult<'tcx, Self>; -} - -/////////////////////////////////////////////////////////////////////////// -// Relate impls - -#[inline] -pub fn relate_args_invariantly<'tcx, R: TypeRelation<'tcx>>( - relation: &mut R, - a_arg: GenericArgsRef<'tcx>, - b_arg: GenericArgsRef<'tcx>, -) -> RelateResult<'tcx, GenericArgsRef<'tcx>> { - relation.tcx().mk_args_from_iter(iter::zip(a_arg, b_arg).map(|(a, b)| { - relation.relate_with_variance(ty::Invariant, ty::VarianceDiagInfo::default(), a, b) - })) -} - -pub fn relate_args_with_variances<'tcx, R: TypeRelation<'tcx>>( - relation: &mut R, - ty_def_id: DefId, - variances: &[ty::Variance], - a_arg: GenericArgsRef<'tcx>, - b_arg: GenericArgsRef<'tcx>, - fetch_ty_for_diag: bool, -) -> RelateResult<'tcx, GenericArgsRef<'tcx>> { - let tcx = relation.tcx(); - - let mut cached_ty = None; - let params = iter::zip(a_arg, b_arg).enumerate().map(|(i, (a, b))| { - let variance = variances[i]; - let variance_info = if variance == ty::Invariant && fetch_ty_for_diag { - let ty = - *cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).instantiate(tcx, a_arg)); - ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() } - } else { - ty::VarianceDiagInfo::default() - }; - relation.relate_with_variance(variance, variance_info, a, b) - }); - - tcx.mk_args_from_iter(params) -} - -impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::FnSig<'tcx>, - b: ty::FnSig<'tcx>, - ) -> RelateResult<'tcx, ty::FnSig<'tcx>> { - let tcx = relation.tcx(); - - if a.c_variadic != b.c_variadic { - return Err(TypeError::VariadicMismatch(expected_found(a.c_variadic, b.c_variadic))); - } - let safety = relation.relate(a.safety, b.safety)?; - let abi = relation.relate(a.abi, b.abi)?; - - if a.inputs().len() != b.inputs().len() { - return Err(TypeError::ArgCount); - } - - let inputs_and_output = iter::zip(a.inputs(), b.inputs()) - .map(|(&a, &b)| ((a, b), false)) - .chain(iter::once(((a.output(), b.output()), true))) - .map(|((a, b), is_output)| { - if is_output { - relation.relate(a, b) - } else { - relation.relate_with_variance( - ty::Contravariant, - ty::VarianceDiagInfo::default(), - a, - b, - ) - } - }) - .enumerate() - .map(|(i, r)| match r { - Err(TypeError::Sorts(exp_found) | TypeError::ArgumentSorts(exp_found, _)) => { - Err(TypeError::ArgumentSorts(exp_found, i)) - } - Err(TypeError::Mutability | TypeError::ArgumentMutability(_)) => { - Err(TypeError::ArgumentMutability(i)) - } - r => r, - }); - Ok(ty::FnSig { - inputs_and_output: tcx.mk_type_list_from_iter(inputs_and_output)?, - c_variadic: a.c_variadic, - safety, - abi, - }) - } -} - -impl<'tcx> Relate<'tcx> for ty::BoundConstness { - fn relate<R: TypeRelation<'tcx>>( - _relation: &mut R, - a: ty::BoundConstness, - b: ty::BoundConstness, - ) -> RelateResult<'tcx, ty::BoundConstness> { - if a != b { Err(TypeError::ConstnessMismatch(expected_found(a, b))) } else { Ok(a) } - } -} - -impl<'tcx> Relate<'tcx> for hir::Safety { - fn relate<R: TypeRelation<'tcx>>( - _relation: &mut R, - a: hir::Safety, - b: hir::Safety, - ) -> RelateResult<'tcx, hir::Safety> { - if a != b { Err(TypeError::SafetyMismatch(expected_found(a, b))) } else { Ok(a) } - } -} - -impl<'tcx> Relate<'tcx> for abi::Abi { - fn relate<R: TypeRelation<'tcx>>( - _relation: &mut R, - a: abi::Abi, - b: abi::Abi, - ) -> RelateResult<'tcx, abi::Abi> { - if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(expected_found(a, b))) } - } -} - -impl<'tcx> Relate<'tcx> for ty::AliasTy<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::AliasTy<'tcx>, - b: ty::AliasTy<'tcx>, - ) -> RelateResult<'tcx, ty::AliasTy<'tcx>> { - if a.def_id != b.def_id { - Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id))) - } else { - let args = match a.kind(relation.tcx()) { - ty::Opaque => relate_args_with_variances( - relation, - a.def_id, - relation.tcx().variances_of(a.def_id), - a.args, - b.args, - false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle - )?, - ty::Projection | ty::Weak | ty::Inherent => { - relate_args_invariantly(relation, a.args, b.args)? - } - }; - Ok(ty::AliasTy::new(relation.tcx(), a.def_id, args)) - } - } -} - -impl<'tcx> Relate<'tcx> for ty::AliasTerm<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::AliasTerm<'tcx>, - b: ty::AliasTerm<'tcx>, - ) -> RelateResult<'tcx, ty::AliasTerm<'tcx>> { - if a.def_id != b.def_id { - Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id))) - } else { - let args = match a.kind(relation.tcx()) { - ty::AliasTermKind::OpaqueTy => relate_args_with_variances( - relation, - a.def_id, - relation.tcx().variances_of(a.def_id), - a.args, - b.args, - false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle - )?, - ty::AliasTermKind::ProjectionTy - | ty::AliasTermKind::WeakTy - | ty::AliasTermKind::InherentTy - | ty::AliasTermKind::UnevaluatedConst - | ty::AliasTermKind::ProjectionConst => { - relate_args_invariantly(relation, a.args, b.args)? - } - }; - Ok(ty::AliasTerm::new(relation.tcx(), a.def_id, args)) - } - } -} +pub use rustc_type_ir::relate::*; -impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::ExistentialProjection<'tcx>, - b: ty::ExistentialProjection<'tcx>, - ) -> RelateResult<'tcx, ty::ExistentialProjection<'tcx>> { - if a.def_id != b.def_id { - Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id))) - } else { - let term = relation.relate_with_variance( - ty::Invariant, - ty::VarianceDiagInfo::default(), - a.term, - b.term, - )?; - let args = relation.relate_with_variance( - ty::Invariant, - ty::VarianceDiagInfo::default(), - a.args, - b.args, - )?; - Ok(ty::ExistentialProjection { def_id: a.def_id, args, term }) - } - } -} - -impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::TraitRef<'tcx>, - b: ty::TraitRef<'tcx>, - ) -> RelateResult<'tcx, ty::TraitRef<'tcx>> { - // Different traits cannot be related. - if a.def_id != b.def_id { - Err(TypeError::Traits(expected_found(a.def_id, b.def_id))) - } else { - let args = relate_args_invariantly(relation, a.args, b.args)?; - Ok(ty::TraitRef::new(relation.tcx(), a.def_id, args)) - } - } -} - -impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::ExistentialTraitRef<'tcx>, - b: ty::ExistentialTraitRef<'tcx>, - ) -> RelateResult<'tcx, ty::ExistentialTraitRef<'tcx>> { - // Different traits cannot be related. - if a.def_id != b.def_id { - Err(TypeError::Traits(expected_found(a.def_id, b.def_id))) - } else { - let args = relate_args_invariantly(relation, a.args, b.args)?; - Ok(ty::ExistentialTraitRef { def_id: a.def_id, args }) - } - } -} +use crate::ty::error::{ExpectedFound, TypeError}; +use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; +use crate::ty::{self as ty, Ty, TyCtxt}; -#[derive(PartialEq, Copy, Debug, Clone, TypeFoldable, TypeVisitable)] -struct CoroutineWitness<'tcx>(&'tcx ty::List<Ty<'tcx>>); +pub type RelateResult<'tcx, T> = rustc_type_ir::relate::RelateResult<TyCtxt<'tcx>, T>; -impl<'tcx> Relate<'tcx> for CoroutineWitness<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: CoroutineWitness<'tcx>, - b: CoroutineWitness<'tcx>, - ) -> RelateResult<'tcx, CoroutineWitness<'tcx>> { - assert_eq!(a.0.len(), b.0.len()); - let tcx = relation.tcx(); - let types = - tcx.mk_type_list_from_iter(iter::zip(a.0, b.0).map(|(a, b)| relation.relate(a, b)))?; - Ok(CoroutineWitness(types)) - } +/// Whether aliases should be related structurally or not. Used +/// to adjust the behavior of generalization and combine. +/// +/// This should always be `No` unless in a few special-cases when +/// instantiating canonical responses and in the new solver. Each +/// such case should have a comment explaining why it is used. +#[derive(Debug, Copy, Clone)] +pub enum StructurallyRelateAliases { + Yes, + No, } -impl<'tcx> Relate<'tcx> for ImplSubject<'tcx> { +impl<'tcx> Relate<TyCtxt<'tcx>> for ty::ImplSubject<'tcx> { #[inline] - fn relate<R: TypeRelation<'tcx>>( + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, - a: ImplSubject<'tcx>, - b: ImplSubject<'tcx>, - ) -> RelateResult<'tcx, ImplSubject<'tcx>> { + a: ty::ImplSubject<'tcx>, + b: ty::ImplSubject<'tcx>, + ) -> RelateResult<'tcx, ty::ImplSubject<'tcx>> { match (a, b) { - (ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => { + (ty::ImplSubject::Trait(trait_ref_a), ty::ImplSubject::Trait(trait_ref_b)) => { let trait_ref = ty::TraitRef::relate(relation, trait_ref_a, trait_ref_b)?; - Ok(ImplSubject::Trait(trait_ref)) + Ok(ty::ImplSubject::Trait(trait_ref)) } - (ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => { + (ty::ImplSubject::Inherent(ty_a), ty::ImplSubject::Inherent(ty_b)) => { let ty = Ty::relate(relation, ty_a, ty_b)?; - Ok(ImplSubject::Inherent(ty)) + Ok(ty::ImplSubject::Inherent(ty)) } - (ImplSubject::Trait(_), ImplSubject::Inherent(_)) - | (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => { + (ty::ImplSubject::Trait(_), ty::ImplSubject::Inherent(_)) + | (ty::ImplSubject::Inherent(_), ty::ImplSubject::Trait(_)) => { bug!("can not relate TraitRef and Ty"); } } } } -impl<'tcx> Relate<'tcx> for Ty<'tcx> { +impl<'tcx> Relate<TyCtxt<'tcx>> for Ty<'tcx> { #[inline] - fn relate<R: TypeRelation<'tcx>>( + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, a: Ty<'tcx>, b: Ty<'tcx>, @@ -386,9 +57,9 @@ impl<'tcx> Relate<'tcx> for Ty<'tcx> { } } -impl<'tcx> Relate<'tcx> for Pattern<'tcx> { +impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Pattern<'tcx> { #[inline] - fn relate<R: TypeRelation<'tcx>>( + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, a: Self, b: Self, @@ -416,303 +87,8 @@ impl<'tcx> Relate<'tcx> for Pattern<'tcx> { } } -/// Relates `a` and `b` structurally, calling the relation for all nested values. -/// Any semantic equality, e.g. of projections, and inference variables have to be -/// handled by the caller. -#[instrument(level = "trace", skip(relation), ret)] -pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( - relation: &mut R, - a: Ty<'tcx>, - b: Ty<'tcx>, -) -> RelateResult<'tcx, Ty<'tcx>> { - let tcx = relation.tcx(); - match (a.kind(), b.kind()) { - (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { - // The caller should handle these cases! - bug!("var types encountered in structurally_relate_tys") - } - - (ty::Bound(..), _) | (_, ty::Bound(..)) => { - bug!("bound types encountered in structurally_relate_tys") - } - - (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(Ty::new_error(tcx, guar)), - - (&ty::Never, _) - | (&ty::Char, _) - | (&ty::Bool, _) - | (&ty::Int(_), _) - | (&ty::Uint(_), _) - | (&ty::Float(_), _) - | (&ty::Str, _) - if a == b => - { - Ok(a) - } - - (ty::Param(a_p), ty::Param(b_p)) if a_p.index == b_p.index => { - debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name"); - Ok(a) - } - - (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a), - - (&ty::Adt(a_def, a_args), &ty::Adt(b_def, b_args)) if a_def == b_def => { - let args = relation.relate_item_args(a_def.did(), a_args, b_args)?; - Ok(Ty::new_adt(tcx, a_def, args)) - } - - (&ty::Foreign(a_id), &ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(tcx, a_id)), - - (&ty::Dynamic(a_obj, a_region, a_repr), &ty::Dynamic(b_obj, b_region, b_repr)) - if a_repr == b_repr => - { - Ok(Ty::new_dynamic( - tcx, - relation.relate(a_obj, b_obj)?, - relation.relate(a_region, b_region)?, - a_repr, - )) - } - - (&ty::Coroutine(a_id, a_args), &ty::Coroutine(b_id, b_args)) if a_id == b_id => { - // All Coroutine types with the same id represent - // the (anonymous) type of the same coroutine expression. So - // all of their regions should be equated. - let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_coroutine(tcx, a_id, args)) - } - - (&ty::CoroutineWitness(a_id, a_args), &ty::CoroutineWitness(b_id, b_args)) - if a_id == b_id => - { - // All CoroutineWitness types with the same id represent - // the (anonymous) type of the same coroutine expression. So - // all of their regions should be equated. - let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_coroutine_witness(tcx, a_id, args)) - } - - (&ty::Closure(a_id, a_args), &ty::Closure(b_id, b_args)) if a_id == b_id => { - // All Closure types with the same id represent - // the (anonymous) type of the same closure expression. So - // all of their regions should be equated. - let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_closure(tcx, a_id, args)) - } - - (&ty::CoroutineClosure(a_id, a_args), &ty::CoroutineClosure(b_id, b_args)) - if a_id == b_id => - { - let args = relate_args_invariantly(relation, a_args, b_args)?; - Ok(Ty::new_coroutine_closure(tcx, a_id, args)) - } - - (&ty::RawPtr(a_ty, a_mutbl), &ty::RawPtr(b_ty, b_mutbl)) => { - if a_mutbl != b_mutbl { - return Err(TypeError::Mutability); - } - - let (variance, info) = match a_mutbl { - hir::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None), - hir::Mutability::Mut => { - (ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) - } - }; - - let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?; - - Ok(Ty::new_ptr(tcx, ty, a_mutbl)) - } - - (&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => { - if a_mutbl != b_mutbl { - return Err(TypeError::Mutability); - } - - let (variance, info) = match a_mutbl { - hir::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None), - hir::Mutability::Mut => { - (ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) - } - }; - - let r = relation.relate(a_r, b_r)?; - let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?; - - Ok(Ty::new_ref(tcx, r, ty, a_mutbl)) - } - - (&ty::Array(a_t, sz_a), &ty::Array(b_t, sz_b)) => { - let t = relation.relate(a_t, b_t)?; - match relation.relate(sz_a, sz_b) { - Ok(sz) => Ok(Ty::new_array_with_const_len(tcx, t, sz)), - Err(err) => { - // Check whether the lengths are both concrete/known values, - // but are unequal, for better diagnostics. - let sz_a = sz_a.try_to_target_usize(tcx); - let sz_b = sz_b.try_to_target_usize(tcx); - - match (sz_a, sz_b) { - (Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => { - Err(TypeError::FixedArraySize(expected_found(sz_a_val, sz_b_val))) - } - _ => Err(err), - } - } - } - } - - (&ty::Slice(a_t), &ty::Slice(b_t)) => { - let t = relation.relate(a_t, b_t)?; - Ok(Ty::new_slice(tcx, t)) - } - - (&ty::Tuple(as_), &ty::Tuple(bs)) => { - if as_.len() == bs.len() { - Ok(Ty::new_tup_from_iter( - tcx, - iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)), - )?) - } else if !(as_.is_empty() || bs.is_empty()) { - Err(TypeError::TupleSize(expected_found(as_.len(), bs.len()))) - } else { - Err(TypeError::Sorts(expected_found(a, b))) - } - } - - (&ty::FnDef(a_def_id, a_args), &ty::FnDef(b_def_id, b_args)) if a_def_id == b_def_id => { - let args = relation.relate_item_args(a_def_id, a_args, b_args)?; - Ok(Ty::new_fn_def(tcx, a_def_id, args)) - } - - (&ty::FnPtr(a_fty), &ty::FnPtr(b_fty)) => { - let fty = relation.relate(a_fty, b_fty)?; - Ok(Ty::new_fn_ptr(tcx, fty)) - } - - // Alias tend to mostly already be handled downstream due to normalization. - (&ty::Alias(a_kind, a_data), &ty::Alias(b_kind, b_data)) => { - let alias_ty = relation.relate(a_data, b_data)?; - assert_eq!(a_kind, b_kind); - Ok(Ty::new_alias(tcx, a_kind, alias_ty)) - } - - (&ty::Pat(a_ty, a_pat), &ty::Pat(b_ty, b_pat)) => { - let ty = relation.relate(a_ty, b_ty)?; - let pat = relation.relate(a_pat, b_pat)?; - Ok(Ty::new_pat(tcx, ty, pat)) - } - - _ => Err(TypeError::Sorts(expected_found(a, b))), - } -} - -/// Relates `a` and `b` structurally, calling the relation for all nested values. -/// Any semantic equality, e.g. of unevaluated consts, and inference variables have -/// to be handled by the caller. -/// -/// FIXME: This is not totally structual, which probably should be fixed. -/// See the HACKs below. -pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>( - relation: &mut R, - mut a: ty::Const<'tcx>, - mut b: ty::Const<'tcx>, -) -> RelateResult<'tcx, ty::Const<'tcx>> { - debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); - let tcx = relation.tcx(); - - if tcx.features().generic_const_exprs { - a = tcx.expand_abstract_consts(a); - b = tcx.expand_abstract_consts(b); - } - - debug!("{}.structurally_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b); - - // Currently, the values that can be unified are primitive types, - // and those that derive both `PartialEq` and `Eq`, corresponding - // to structural-match types. - let is_match = match (a.kind(), b.kind()) { - (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { - // The caller should handle these cases! - bug!("var types encountered in structurally_relate_consts: {:?} {:?}", a, b) - } - - (ty::ConstKind::Error(_), _) => return Ok(a), - (_, ty::ConstKind::Error(_)) => return Ok(b), - - (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index == b_p.index => { - debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name"); - true - } - (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2, - (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val, - - // While this is slightly incorrect, it shouldn't matter for `min_const_generics` - // and is the better alternative to waiting until `generic_const_exprs` can - // be stabilized. - (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def => { - assert_eq!(a.ty(), b.ty()); - let args = relation.relate_with_variance( - ty::Variance::Invariant, - ty::VarianceDiagInfo::default(), - au.args, - bu.args, - )?; - return Ok(ty::Const::new_unevaluated( - tcx, - ty::UnevaluatedConst { def: au.def, args }, - a.ty(), - )); - } - // Before calling relate on exprs, it is necessary to ensure that the nested consts - // have identical types. - (ty::ConstKind::Expr(ae), ty::ConstKind::Expr(be)) => { - let r = relation; - - // FIXME(generic_const_exprs): is it possible to relate two consts which are not identical - // exprs? Should we care about that? - // FIXME(generic_const_exprs): relating the `ty()`s is a little weird since it is supposed to - // ICE If they mismatch. Unfortunately `ConstKind::Expr` is a little special and can be thought - // of as being generic over the argument types, however this is implicit so these types don't get - // related when we relate the args of the item this const arg is for. - let expr = match (ae, be) { - (Expr::Binop(a_op, al, ar), Expr::Binop(b_op, bl, br)) if a_op == b_op => { - r.relate(al.ty(), bl.ty())?; - r.relate(ar.ty(), br.ty())?; - Expr::Binop(a_op, r.consts(al, bl)?, r.consts(ar, br)?) - } - (Expr::UnOp(a_op, av), Expr::UnOp(b_op, bv)) if a_op == b_op => { - r.relate(av.ty(), bv.ty())?; - Expr::UnOp(a_op, r.consts(av, bv)?) - } - (Expr::Cast(ak, av, at), Expr::Cast(bk, bv, bt)) if ak == bk => { - r.relate(av.ty(), bv.ty())?; - Expr::Cast(ak, r.consts(av, bv)?, r.tys(at, bt)?) - } - (Expr::FunctionCall(af, aa), Expr::FunctionCall(bf, ba)) - if aa.len() == ba.len() => - { - r.relate(af.ty(), bf.ty())?; - let func = r.consts(af, bf)?; - let mut related_args = Vec::with_capacity(aa.len()); - for (a_arg, b_arg) in aa.iter().zip(ba.iter()) { - related_args.push(r.consts(a_arg, b_arg)?); - } - let related_args = tcx.mk_const_list(&related_args); - Expr::FunctionCall(func, related_args) - } - _ => return Err(TypeError::ConstMismatch(expected_found(a, b))), - }; - return Ok(ty::Const::new_expr(tcx, expr, a.ty())); - } - _ => false, - }; - if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(a, b))) } -} - -impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> { - fn relate<R: TypeRelation<'tcx>>( +impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, a: Self, b: Self, @@ -730,44 +106,65 @@ impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> { b_v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); b_v.dedup(); if a_v.len() != b_v.len() { - return Err(TypeError::ExistentialMismatch(expected_found(a, b))); + return Err(TypeError::ExistentialMismatch(ExpectedFound::new(true, a, b))); } let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| { match (ep_a.skip_binder(), ep_b.skip_binder()) { - (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( + (ty::ExistentialPredicate::Trait(a), ty::ExistentialPredicate::Trait(b)) => { + Ok(ep_a.rebind(ty::ExistentialPredicate::Trait( 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))), + ( + ty::ExistentialPredicate::Projection(a), + ty::ExistentialPredicate::Projection(b), + ) => Ok(ep_a.rebind(ty::ExistentialPredicate::Projection( + relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(), + ))), + ( + ty::ExistentialPredicate::AutoTrait(a), + ty::ExistentialPredicate::AutoTrait(b), + ) if a == b => Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))), + _ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(true, a, b))), } }); tcx.mk_poly_existential_predicates_from_iter(v) } } -impl<'tcx> Relate<'tcx> for GenericArgsRef<'tcx> { - fn relate<R: TypeRelation<'tcx>>( +impl<'tcx> Relate<TyCtxt<'tcx>> for hir::Safety { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( + _relation: &mut R, + a: hir::Safety, + b: hir::Safety, + ) -> RelateResult<'tcx, hir::Safety> { + if a != b { Err(TypeError::SafetyMismatch(ExpectedFound::new(true, a, b))) } else { Ok(a) } + } +} + +impl<'tcx> Relate<TyCtxt<'tcx>> for abi::Abi { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( + _relation: &mut R, + a: abi::Abi, + b: abi::Abi, + ) -> RelateResult<'tcx, abi::Abi> { + if a == b { Ok(a) } else { Err(TypeError::AbiMismatch(ExpectedFound::new(true, a, b))) } + } +} + +impl<'tcx> Relate<TyCtxt<'tcx>> for ty::GenericArgsRef<'tcx> { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, - a: GenericArgsRef<'tcx>, - b: GenericArgsRef<'tcx>, - ) -> RelateResult<'tcx, GenericArgsRef<'tcx>> { + a: ty::GenericArgsRef<'tcx>, + b: ty::GenericArgsRef<'tcx>, + ) -> RelateResult<'tcx, ty::GenericArgsRef<'tcx>> { relate_args_invariantly(relation, a, b) } } -impl<'tcx> Relate<'tcx> for ty::Region<'tcx> { - fn relate<R: TypeRelation<'tcx>>( +impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Region<'tcx> { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, a: ty::Region<'tcx>, b: ty::Region<'tcx>, @@ -776,8 +173,8 @@ impl<'tcx> Relate<'tcx> for ty::Region<'tcx> { } } -impl<'tcx> Relate<'tcx> for ty::Const<'tcx> { - fn relate<R: TypeRelation<'tcx>>( +impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Const<'tcx> { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, a: ty::Const<'tcx>, b: ty::Const<'tcx>, @@ -786,85 +183,70 @@ impl<'tcx> Relate<'tcx> for ty::Const<'tcx> { } } -impl<'tcx, T: Relate<'tcx>> Relate<'tcx> for ty::Binder<'tcx, T> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> { - relation.binders(a, b) +impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Expr<'tcx> { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( + relation: &mut R, + ae: ty::Expr<'tcx>, + be: ty::Expr<'tcx>, + ) -> RelateResult<'tcx, ty::Expr<'tcx>> { + // FIXME(generic_const_exprs): is it possible to relate two consts which are not identical + // exprs? Should we care about that? + // FIXME(generic_const_exprs): relating the `ty()`s is a little weird since it is supposed to + // ICE If they mismatch. Unfortunately `ConstKind::Expr` is a little special and can be thought + // of as being generic over the argument types, however this is implicit so these types don't get + // related when we relate the args of the item this const arg is for. + match (ae.kind, be.kind) { + (ty::ExprKind::Binop(a_binop), ty::ExprKind::Binop(b_binop)) if a_binop == b_binop => {} + (ty::ExprKind::UnOp(a_unop), ty::ExprKind::UnOp(b_unop)) if a_unop == b_unop => {} + (ty::ExprKind::FunctionCall, ty::ExprKind::FunctionCall) => {} + (ty::ExprKind::Cast(a_kind), ty::ExprKind::Cast(b_kind)) if a_kind == b_kind => {} + _ => return Err(TypeError::Mismatch), + } + + let args = relation.relate(ae.args(), be.args())?; + Ok(ty::Expr::new(ae.kind, args)) } } -impl<'tcx> Relate<'tcx> for GenericArg<'tcx> { - fn relate<R: TypeRelation<'tcx>>( +impl<'tcx> Relate<TyCtxt<'tcx>> for ty::GenericArg<'tcx> { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, - a: GenericArg<'tcx>, - b: GenericArg<'tcx>, - ) -> RelateResult<'tcx, GenericArg<'tcx>> { + a: ty::GenericArg<'tcx>, + b: ty::GenericArg<'tcx>, + ) -> RelateResult<'tcx, ty::GenericArg<'tcx>> { match (a.unpack(), b.unpack()) { - (GenericArgKind::Lifetime(a_lt), GenericArgKind::Lifetime(b_lt)) => { + (ty::GenericArgKind::Lifetime(a_lt), ty::GenericArgKind::Lifetime(b_lt)) => { Ok(relation.relate(a_lt, b_lt)?.into()) } - (GenericArgKind::Type(a_ty), GenericArgKind::Type(b_ty)) => { + (ty::GenericArgKind::Type(a_ty), ty::GenericArgKind::Type(b_ty)) => { Ok(relation.relate(a_ty, b_ty)?.into()) } - (GenericArgKind::Const(a_ct), GenericArgKind::Const(b_ct)) => { + (ty::GenericArgKind::Const(a_ct), ty::GenericArgKind::Const(b_ct)) => { Ok(relation.relate(a_ct, b_ct)?.into()) } - (GenericArgKind::Lifetime(unpacked), x) => { + (ty::GenericArgKind::Lifetime(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } - (GenericArgKind::Type(unpacked), x) => { + (ty::GenericArgKind::Type(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } - (GenericArgKind::Const(unpacked), x) => { + (ty::GenericArgKind::Const(unpacked), x) => { bug!("impossible case reached: can't relate: {:?} with {:?}", unpacked, x) } } } } -impl<'tcx> Relate<'tcx> for ty::PredicatePolarity { - fn relate<R: TypeRelation<'tcx>>( - _relation: &mut R, - a: ty::PredicatePolarity, - b: ty::PredicatePolarity, - ) -> RelateResult<'tcx, ty::PredicatePolarity> { - if a != b { Err(TypeError::PolarityMismatch(expected_found(a, b))) } else { Ok(a) } - } -} - -impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> { - fn relate<R: TypeRelation<'tcx>>( - relation: &mut R, - a: ty::TraitPredicate<'tcx>, - b: ty::TraitPredicate<'tcx>, - ) -> RelateResult<'tcx, ty::TraitPredicate<'tcx>> { - Ok(ty::TraitPredicate { - trait_ref: relation.relate(a.trait_ref, b.trait_ref)?, - polarity: relation.relate(a.polarity, b.polarity)?, - }) - } -} - -impl<'tcx> Relate<'tcx> for Term<'tcx> { - fn relate<R: TypeRelation<'tcx>>( +impl<'tcx> Relate<TyCtxt<'tcx>> for ty::Term<'tcx> { + fn relate<R: TypeRelation<TyCtxt<'tcx>>>( relation: &mut R, a: Self, b: Self, ) -> RelateResult<'tcx, Self> { Ok(match (a.unpack(), b.unpack()) { - (TermKind::Ty(a), TermKind::Ty(b)) => relation.relate(a, b)?.into(), - (TermKind::Const(a), TermKind::Const(b)) => relation.relate(a, b)?.into(), + (ty::TermKind::Ty(a), ty::TermKind::Ty(b)) => relation.relate(a, b)?.into(), + (ty::TermKind::Const(a), ty::TermKind::Const(b)) => relation.relate(a, b)?.into(), _ => return Err(TypeError::Mismatch), }) } } - -/////////////////////////////////////////////////////////////////////////// -// Error handling - -pub fn expected_found<T>(a: T, b: T) -> ExpectedFound<T> { - ExpectedFound::new(true, a, b) -} diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 90791bdd20d..cc6b1d57f87 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -147,14 +147,27 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> { this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { - match this.data { - ty::Expr::Binop(op, lhs, rhs) => { - write!(f, "({op:?}: {:?}, {:?})", &this.wrap(lhs), &this.wrap(rhs)) + match this.data.kind { + ty::ExprKind::Binop(op) => { + let (lhs_ty, rhs_ty, lhs, rhs) = this.data.binop_args(); + write!( + f, + "({op:?}: ({:?}: {:?}), ({:?}: {:?}))", + &this.wrap(lhs), + &this.wrap(lhs_ty), + &this.wrap(rhs), + &this.wrap(rhs_ty), + ) } - ty::Expr::UnOp(op, rhs) => write!(f, "({op:?}: {:?})", &this.wrap(rhs)), - ty::Expr::FunctionCall(func, args) => { - write!(f, "{:?}(", &this.wrap(func))?; - for arg in args.as_slice().iter().rev().skip(1).rev() { + ty::ExprKind::UnOp(op) => { + let (rhs_ty, rhs) = this.data.unop_args(); + write!(f, "({op:?}: ({:?}: {:?}))", &this.wrap(rhs), &this.wrap(rhs_ty)) + } + ty::ExprKind::FunctionCall => { + let (func_ty, func, args) = this.data.call_args(); + let args = args.collect::<Vec<_>>(); + write!(f, "({:?}: {:?})(", &this.wrap(func), &this.wrap(func_ty))?; + for arg in args.iter().rev().skip(1).rev() { write!(f, "{:?}, ", &this.wrap(arg))?; } if let Some(arg) = args.last() { @@ -163,8 +176,15 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::consts::Expr<'tcx> { write!(f, ")") } - ty::Expr::Cast(cast_kind, lhs, rhs) => { - write!(f, "({cast_kind:?}: {:?}, {:?})", &this.wrap(lhs), &this.wrap(rhs)) + ty::ExprKind::Cast(kind) => { + let (value_ty, value, to_ty) = this.data.cast_args(); + write!( + f, + "({kind:?}: ({:?}: {:?}), {:?})", + &this.wrap(value), + &this.wrap(value_ty), + &this.wrap(to_ty) + ) } } } @@ -181,26 +201,21 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::Const<'tcx> { f: &mut core::fmt::Formatter<'_>, ) -> core::fmt::Result { // If this is a value, we spend some effort to make it look nice. - if let ConstKind::Value(_) = this.data.kind() { + if let ConstKind::Value(_, _) = this.data.kind() { return ty::tls::with(move |tcx| { // Somehow trying to lift the valtree results in lifetime errors, so we lift the // entire constant. let lifted = tcx.lift(*this.data).unwrap(); - let ConstKind::Value(valtree) = lifted.kind() else { + let ConstKind::Value(ty, valtree) = lifted.kind() else { bug!("we checked that this is a valtree") }; let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); - cx.pretty_print_const_valtree(valtree, lifted.ty(), /*print_ty*/ true)?; + cx.pretty_print_const_valtree(valtree, ty, /*print_ty*/ true)?; f.write_str(&cx.into_buffer()) }); } // Fall back to something verbose. - write!( - f, - "{kind:?}: {ty:?}", - ty = &this.map(|data| data.ty()), - kind = &this.map(|data| data.kind()) - ) + write!(f, "{kind:?}", kind = &this.map(|data| data.kind())) } } @@ -281,7 +296,6 @@ TrivialTypeTraversalImpls! { ::rustc_target::abi::FieldIdx, ::rustc_target::abi::VariantIdx, crate::middle::region::Scope, - crate::ty::FloatTy, ::rustc_ast::InlineAsmOptions, ::rustc_ast::InlineAsmTemplatePiece, ::rustc_ast::NodeId, @@ -301,7 +315,7 @@ TrivialTypeTraversalImpls! { crate::traits::Reveal, crate::ty::adjustment::AutoBorrowMutability, crate::ty::AdtKind, - crate::ty::BoundConstness, + crate::ty::BoundRegion, // Including `BoundRegionKind` is a *bit* dubious, but direct // references to bound region appear in `ty::Error`, and aren't // really meant to be folded. In general, we can only fold a fully @@ -309,16 +323,11 @@ TrivialTypeTraversalImpls! { crate::ty::BoundRegionKind, crate::ty::AssocItem, crate::ty::AssocKind, - crate::ty::AliasTyKind, crate::ty::Placeholder<crate::ty::BoundRegion>, crate::ty::Placeholder<crate::ty::BoundTy>, crate::ty::Placeholder<ty::BoundVar>, crate::ty::LateParamRegion, - crate::ty::InferTy, - crate::ty::IntVarValue, crate::ty::adjustment::PointerCoercion, - crate::ty::RegionVid, - crate::ty::Variance, ::rustc_span::Span, ::rustc_span::symbol::Ident, ::rustc_errors::ErrorGuaranteed, @@ -627,7 +636,6 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> { self, folder: &mut F, ) -> Result<Self, F::Error> { - let ty = self.ty().try_fold_with(folder)?; let kind = match self.kind() { ConstKind::Param(p) => ConstKind::Param(p.try_fold_with(folder)?), ConstKind::Infer(i) => ConstKind::Infer(i.try_fold_with(folder)?), @@ -636,21 +644,18 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> { } ConstKind::Placeholder(p) => ConstKind::Placeholder(p.try_fold_with(folder)?), ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.try_fold_with(folder)?), - ConstKind::Value(v) => ConstKind::Value(v.try_fold_with(folder)?), + ConstKind::Value(t, v) => { + ConstKind::Value(t.try_fold_with(folder)?, v.try_fold_with(folder)?) + } ConstKind::Error(e) => ConstKind::Error(e.try_fold_with(folder)?), ConstKind::Expr(e) => ConstKind::Expr(e.try_fold_with(folder)?), }; - if ty != self.ty() || kind != self.kind() { - Ok(folder.interner().mk_ct_from_kind(kind, ty)) - } else { - Ok(self) - } + if kind != self.kind() { Ok(folder.interner().mk_ct_from_kind(kind)) } else { Ok(self) } } } impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> { fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result { - try_visit!(self.ty().visit_with(visitor)); match self.kind() { ConstKind::Param(p) => p.visit_with(visitor), ConstKind::Infer(i) => i.visit_with(visitor), @@ -660,7 +665,10 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> { } ConstKind::Placeholder(p) => p.visit_with(visitor), ConstKind::Unevaluated(uv) => uv.visit_with(visitor), - ConstKind::Value(v) => v.visit_with(visitor), + ConstKind::Value(t, v) => { + try_visit!(t.visit_with(visitor)); + v.visit_with(visitor) + } ConstKind::Error(e) => e.visit_with(visitor), ConstKind::Expr(e) => e.visit_with(visitor), } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 879396b0678..ba9ed0d5b70 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -21,6 +21,7 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; use rustc_target::spec::abi; +use rustc_type_ir::visit::TypeVisitableExt; use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::iter; @@ -339,6 +340,27 @@ impl ParamConst { pub fn for_def(def: &ty::GenericParamDef) -> ParamConst { ParamConst::new(def.index, def.name) } + + pub fn find_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> { + let mut candidates = env.caller_bounds().iter().filter_map(|clause| { + // `ConstArgHasType` are never desugared to be higher ranked. + match clause.kind().skip_binder() { + ty::ClauseKind::ConstArgHasType(param_ct, ty) => { + assert!(!(param_ct, ty).has_escaping_bound_vars()); + + match param_ct.kind() { + ty::ConstKind::Param(param_ct) if param_ct.index == self.index => Some(ty), + _ => None, + } + } + _ => None, + } + }); + + let ty = candidates.next().unwrap(); + assert!(candidates.next().is_none()); + ty + } } #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] @@ -788,6 +810,31 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> { Ty::new_alias(interner, kind, alias_ty) } + fn new_error(interner: TyCtxt<'tcx>, guar: ErrorGuaranteed) -> Self { + Ty::new_error(interner, guar) + } + + fn new_adt( + interner: TyCtxt<'tcx>, + adt_def: ty::AdtDef<'tcx>, + args: ty::GenericArgsRef<'tcx>, + ) -> Self { + Ty::new_adt(interner, adt_def, args) + } + + fn new_foreign(interner: TyCtxt<'tcx>, def_id: DefId) -> Self { + Ty::new_foreign(interner, def_id) + } + + fn new_dynamic( + interner: TyCtxt<'tcx>, + preds: &'tcx List<ty::PolyExistentialPredicate<'tcx>>, + region: ty::Region<'tcx>, + kind: ty::DynKind, + ) -> Self { + Ty::new_dynamic(interner, preds, region, kind) + } + fn new_coroutine( interner: TyCtxt<'tcx>, def_id: DefId, @@ -796,6 +843,51 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> { Ty::new_coroutine(interner, def_id, args) } + fn new_coroutine_closure( + interner: TyCtxt<'tcx>, + def_id: DefId, + args: ty::GenericArgsRef<'tcx>, + ) -> Self { + Ty::new_coroutine_closure(interner, def_id, args) + } + + fn new_closure(interner: TyCtxt<'tcx>, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Self { + Ty::new_closure(interner, def_id, args) + } + + fn new_coroutine_witness( + interner: TyCtxt<'tcx>, + def_id: DefId, + args: ty::GenericArgsRef<'tcx>, + ) -> Self { + Ty::new_coroutine_witness(interner, def_id, args) + } + + fn new_ptr(interner: TyCtxt<'tcx>, ty: Self, mutbl: hir::Mutability) -> Self { + Ty::new_ptr(interner, ty, mutbl) + } + + fn new_ref( + interner: TyCtxt<'tcx>, + region: ty::Region<'tcx>, + ty: Self, + mutbl: hir::Mutability, + ) -> Self { + Ty::new_ref(interner, region, ty, mutbl) + } + + fn new_array_with_const_len(interner: TyCtxt<'tcx>, ty: Self, len: ty::Const<'tcx>) -> Self { + Ty::new_array_with_const_len(interner, ty, len) + } + + fn new_slice(interner: TyCtxt<'tcx>, ty: Self) -> Self { + Ty::new_slice(interner, ty) + } + + fn new_tup(interner: TyCtxt<'tcx>, tys: &[Ty<'tcx>]) -> Self { + Ty::new_tup(interner, tys) + } + fn new_tup_from_iter<It, T>(interner: TyCtxt<'tcx>, iter: It) -> T::Output where It: Iterator<Item = T>, @@ -822,6 +914,18 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> { ) -> Self { Ty::from_coroutine_closure_kind(interner, kind) } + + fn new_fn_def(interner: TyCtxt<'tcx>, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Self { + Ty::new_fn_def(interner, def_id, args) + } + + fn new_fn_ptr(interner: TyCtxt<'tcx>, sig: ty::Binder<'tcx, ty::FnSig<'tcx>>) -> Self { + Ty::new_fn_ptr(interner, sig) + } + + fn new_pat(interner: TyCtxt<'tcx>, ty: Self, pat: ty::Pattern<'tcx>) -> Self { + Ty::new_pat(interner, ty, pat) + } } /// Type utilities @@ -1790,43 +1894,6 @@ impl<'tcx> rustc_type_ir::inherent::Tys<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx } } -/// Extra information about why we ended up with a particular variance. -/// This is only used to add more information to error messages, and -/// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo` -/// may lead to confusing notes in error messages, it will never cause -/// a miscompilation or unsoundness. -/// -/// When in doubt, use `VarianceDiagInfo::default()` -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] -pub enum VarianceDiagInfo<'tcx> { - /// No additional information - this is the default. - /// We will not add any additional information to error messages. - #[default] - None, - /// We switched our variance because a generic argument occurs inside - /// the invariant generic argument of another type. - Invariant { - /// The generic type containing the generic parameter - /// that changes the variance (e.g. `*mut T`, `MyStruct<T>`) - ty: Ty<'tcx>, - /// The index of the generic parameter being used - /// (e.g. `0` for `*mut T`, `1` for `MyStruct<'CovariantParam, 'InvariantParam>`) - param_index: u32, - }, -} - -impl<'tcx> VarianceDiagInfo<'tcx> { - /// Mirrors `Variance::xform` - used to 'combine' the existing - /// and new `VarianceDiagInfo`s when our variance changes. - pub fn xform(self, other: VarianceDiagInfo<'tcx>) -> VarianceDiagInfo<'tcx> { - // For now, just use the first `VarianceDiagInfo::Invariant` that we see - match self { - VarianceDiagInfo::None => other, - VarianceDiagInfo::Invariant { .. } => self, - } - } -} - // Some types are used a lot. Make sure they don't unintentionally get bigger. #[cfg(target_pointer_width = "64")] mod size_asserts { diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 37a34f28338..4dba97c3b5b 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -206,7 +206,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait // Traits defined in the current crate can't have impls in upstream // crates, so we don't bother querying the cstore. if !trait_id.is_local() { - for &cnum in tcx.used_crates(()).iter() { + for &cnum in tcx.crates(()).iter() { for &(impl_def_id, simplified_self_ty) in tcx.implementations_of_trait((cnum, trait_id)).iter() { @@ -248,7 +248,7 @@ pub(super) fn incoherent_impls_provider( let mut impls = Vec::new(); let mut res = Ok(()); - for cnum in iter::once(LOCAL_CRATE).chain(tcx.used_crates(()).iter().copied()) { + for cnum in iter::once(LOCAL_CRATE).chain(tcx.crates(()).iter().copied()) { let incoherent_impls = match tcx.crate_incoherent_impls((cnum, simp)) { Ok(impls) => impls, Err(e) => { diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 69ea9c9843a..24e3e623ff2 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -217,10 +217,6 @@ pub struct TypeckResults<'tcx> { /// Container types and field indices of `offset_of!` expressions offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)>, - - /// Maps from `HirId`s of const blocks (the `ExprKind::ConstBlock`, not the inner expression's) - /// to the `DefId` of the corresponding inline const. - pub inline_consts: FxIndexMap<ItemLocalId, LocalDefId>, } impl<'tcx> TypeckResults<'tcx> { @@ -253,7 +249,6 @@ impl<'tcx> TypeckResults<'tcx> { treat_byte_string_as_slice: Default::default(), closure_size_eval: Default::default(), offset_of_data: Default::default(), - inline_consts: Default::default(), } } diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index a9421aacff8..e0f204a687f 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -212,38 +212,19 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) } }, GenericArgKind::Lifetime(_) => {} - GenericArgKind::Const(parent_ct) => { - stack.push(parent_ct.ty().into()); - match parent_ct.kind() { - ty::ConstKind::Infer(_) - | ty::ConstKind::Param(_) - | ty::ConstKind::Placeholder(_) - | ty::ConstKind::Bound(..) - | ty::ConstKind::Value(_) - | ty::ConstKind::Error(_) => {} - - ty::ConstKind::Expr(expr) => match expr { - ty::Expr::UnOp(_, v) => push_inner(stack, v.into()), - ty::Expr::Binop(_, l, r) => { - push_inner(stack, r.into()); - push_inner(stack, l.into()) - } - ty::Expr::FunctionCall(func, args) => { - for a in args.iter().rev() { - push_inner(stack, a.into()); - } - push_inner(stack, func.into()); - } - ty::Expr::Cast(_, c, t) => { - push_inner(stack, t.into()); - push_inner(stack, c.into()); - } - }, - - ty::ConstKind::Unevaluated(ct) => { - stack.extend(ct.args.iter().rev()); - } + GenericArgKind::Const(parent_ct) => match parent_ct.kind() { + ty::ConstKind::Infer(_) + | ty::ConstKind::Param(_) + | ty::ConstKind::Placeholder(_) + | ty::ConstKind::Bound(..) + | ty::ConstKind::Error(_) => {} + + ty::ConstKind::Value(ty, _) => stack.push(ty.into()), + + ty::ConstKind::Expr(expr) => stack.extend(expr.args().iter().rev()), + ty::ConstKind::Unevaluated(ct) => { + stack.extend(ct.args.iter().rev()); } - } + }, } } diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index 77f27236437..5d828d0093f 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -either = "1" itertools = "0.12" rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } @@ -24,6 +23,5 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs index 7d7b7caf9ef..f97e9ef60a2 100644 --- a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs +++ b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs @@ -179,18 +179,18 @@ impl MCDCState { } } -pub struct MCDCInfoBuilder { +pub(crate) struct MCDCInfoBuilder { branch_spans: Vec<MCDCBranchSpan>, decision_spans: Vec<MCDCDecisionSpan>, state: MCDCState, } impl MCDCInfoBuilder { - pub fn new() -> Self { + pub(crate) fn new() -> Self { Self { branch_spans: vec![], decision_spans: vec![], state: MCDCState::new() } } - pub fn visit_evaluated_condition( + pub(crate) fn visit_evaluated_condition( &mut self, tcx: TyCtxt<'_>, source_info: SourceInfo, @@ -243,7 +243,7 @@ impl MCDCInfoBuilder { }); } - pub fn into_done(self) -> (Vec<MCDCDecisionSpan>, Vec<MCDCBranchSpan>) { + pub(crate) fn into_done(self) -> (Vec<MCDCDecisionSpan>, Vec<MCDCBranchSpan>) { (self.decision_spans, self.branch_spans) } } diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs index 8bcd429b67e..9607022c6df 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse.rs @@ -91,7 +91,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { } } - pub fn parse_args(&mut self, params: &IndexSlice<ParamId, Param<'tcx>>) -> PResult<()> { + pub(crate) fn parse_args(&mut self, params: &IndexSlice<ParamId, Param<'tcx>>) -> PResult<()> { for param in params.iter() { let (var, span) = { let pat = param.pat.as_ref().unwrap(); @@ -149,7 +149,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { /// /// This allows us to easily parse the basic blocks declarations, local declarations, and /// basic block definitions in order. - pub fn parse_body(&mut self, expr_id: ExprId) -> PResult<()> { + pub(crate) fn parse_body(&mut self, expr_id: ExprId) -> PResult<()> { let body = parse_by_kind!(self, expr_id, _, "whole body", ExprKind::Block { block } => self.thir[*block].expr.unwrap(), ); diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index de748b9c85d..b1a305efa4c 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -12,7 +12,7 @@ use crate::build::expr::as_constant::as_constant_inner; use super::{parse_by_kind, PResult, ParseCtxt}; impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { - pub fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> { + pub(crate) fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> { parse_by_kind!(self, expr_id, _, "statement", @call(mir_storage_live, args) => { Ok(StatementKind::StorageLive(self.parse_local(args[0])?)) @@ -46,7 +46,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { ) } - pub fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> { + pub(crate) fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> { parse_by_kind!(self, expr_id, expr, "terminator", @call(mir_return, _args) => { Ok(TerminatorKind::Return) @@ -261,7 +261,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { ) } - pub fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> { + pub(crate) fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> { parse_by_kind!(self, expr_id, expr, "operand", @call(mir_move, args) => self.parse_place(args[0]).map(Operand::Move), @call(mir_static, args) => self.parse_static(args[0]), diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index b4dd423f344..b783eba8c4e 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -7,7 +7,7 @@ use rustc_middle::mir::interpret::{Allocation, LitToConstError, LitToConstInput, use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::{ - self, CanonicalUserType, CanonicalUserTypeAnnotation, TyCtxt, UserTypeAnnotationIndex, + self, CanonicalUserType, CanonicalUserTypeAnnotation, Ty, TyCtxt, UserTypeAnnotationIndex, }; use rustc_middle::{bug, span_bug}; use rustc_target::abi::Size; @@ -39,7 +39,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } -pub fn as_constant_inner<'tcx>( +pub(crate) fn as_constant_inner<'tcx>( expr: &Expr<'tcx>, push_cuta: impl FnMut(&Box<CanonicalUserType<'tcx>>) -> Option<UserTypeAnnotationIndex>, tcx: TyCtxt<'tcx>, @@ -51,7 +51,7 @@ pub fn as_constant_inner<'tcx>( { Ok(c) => c, Err(LitToConstError::Reported(guar)) => { - Const::Ty(ty::Const::new_error(tcx, guar, ty)) + Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar)) } Err(LitToConstError::TypeError) => { bug!("encountered type error in `lit_to_mir_constant`") @@ -83,8 +83,8 @@ pub fn as_constant_inner<'tcx>( ConstOperand { user_ty, span, const_ } } ExprKind::ConstParam { param, def_id: _ } => { - let const_param = ty::Const::new_param(tcx, param, expr.ty); - let const_ = Const::Ty(const_param); + let const_param = ty::Const::new_param(tcx, param); + let const_ = Const::Ty(expr.ty, const_param); ConstOperand { user_ty: None, span, const_ } } diff --git a/compiler/rustc_mir_build/src/build/expr/mod.rs b/compiler/rustc_mir_build/src/build/expr/mod.rs index dfe85b858cd..3de43a3370f 100644 --- a/compiler/rustc_mir_build/src/build/expr/mod.rs +++ b/compiler/rustc_mir_build/src/build/expr/mod.rs @@ -62,9 +62,9 @@ pub(crate) mod as_constant; mod as_operand; -pub mod as_place; +pub(crate) mod as_place; mod as_rvalue; mod as_temp; -pub mod category; +pub(crate) mod category; mod into; mod stmt; diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 770f689724a..50f4ca2d819 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -456,7 +456,7 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { } #[must_use] -pub fn ref_pat_borrow_kind(ref_mutability: Mutability) -> BorrowKind { +pub(crate) fn ref_pat_borrow_kind(ref_mutability: Mutability) -> BorrowKind { match ref_mutability { Mutability::Mut => BorrowKind::Mut { kind: MutBorrowKind::Default }, Mutability::Not => BorrowKind::Shared, diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 14d1b502474..601e5d4d3dc 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -15,11 +15,10 @@ use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::hir::place::PlaceBase as HirPlaceBase; use rustc_middle::middle::region; -use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::*; use rustc_middle::query::TyCtxtAt; use rustc_middle::thir::{self, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -568,8 +567,11 @@ fn construct_const<'a, 'tcx>( .. }) => (*span, ty.span), Node::AnonConst(ct) => (ct.span, ct.span), - Node::Expr(&hir::Expr { span, kind: hir::ExprKind::ConstBlock(_), .. }) => (span, span), - node => span_bug!(tcx.def_span(def), "can't build MIR for {def:?}: {node:#?}"), + Node::ConstBlock(_) => { + let span = tcx.def_span(def); + (span, span) + } + _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def), }; let infcx = tcx.infer_ctxt().build(); @@ -1011,14 +1013,14 @@ fn parse_float_into_constval<'tcx>( float_ty: ty::FloatTy, neg: bool, ) -> Option<ConstValue<'tcx>> { - parse_float_into_scalar(num, float_ty, neg).map(ConstValue::Scalar) + parse_float_into_scalar(num, float_ty, neg).map(|s| ConstValue::Scalar(s.into())) } pub(crate) fn parse_float_into_scalar( num: Symbol, float_ty: ty::FloatTy, neg: bool, -) -> Option<Scalar> { +) -> Option<ScalarInt> { let num = num.as_str(); match float_ty { // FIXME(f16_f128): When available, compare to the library parser as with `f32` and `f64` @@ -1027,7 +1029,7 @@ pub(crate) fn parse_float_into_scalar( if neg { f = -f; } - Some(Scalar::from_f16(f)) + Some(ScalarInt::from(f)) } ty::FloatTy::F32 => { let Ok(rust_f) = num.parse::<f32>() else { return None }; @@ -1050,7 +1052,7 @@ pub(crate) fn parse_float_into_scalar( f = -f; } - Some(Scalar::from_f32(f)) + Some(ScalarInt::from(f)) } ty::FloatTy::F64 => { let Ok(rust_f) = num.parse::<f64>() else { return None }; @@ -1073,7 +1075,7 @@ pub(crate) fn parse_float_into_scalar( f = -f; } - Some(Scalar::from_f64(f)) + Some(ScalarInt::from(f)) } // FIXME(f16_f128): When available, compare to the library parser as with `f32` and `f64` ty::FloatTy::F128 => { @@ -1081,7 +1083,7 @@ pub(crate) fn parse_float_into_scalar( if neg { f = -f; } - Some(Scalar::from_f128(f)) + Some(ScalarInt::from(f)) } } } diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index c7850c7aea8..5b6de39bb2e 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -97,7 +97,7 @@ use rustc_span::{Span, DUMMY_SP}; use tracing::{debug, instrument}; #[derive(Debug)] -pub struct Scopes<'tcx> { +pub(crate) struct Scopes<'tcx> { scopes: Vec<Scope>, /// The current set of breakable scopes. See module comment for more details. diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 24098282d93..d781fb1c297 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -2,6 +2,7 @@ use crate::build::ExprCategory; use crate::errors::*; use rustc_errors::DiagArgValue; +use rustc_hir::def::DefKind; use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability}; use rustc_middle::mir::BorrowKind; use rustc_middle::span_bug; @@ -88,6 +89,33 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { } } + fn emit_deprecated_safe_fn_call(&self, span: Span, kind: &UnsafeOpKind) -> bool { + match kind { + // Allow calls to deprecated-safe unsafe functions if the caller is + // from an edition before 2024. + &UnsafeOpKind::CallToUnsafeFunction(Some(id)) + if !span.at_least_rust_2024() + && self.tcx.has_attr(id, sym::rustc_deprecated_safe_2024) => + { + self.tcx.emit_node_span_lint( + DEPRECATED_SAFE, + self.hir_context, + span, + CallToDeprecatedSafeFnRequiresUnsafe { + span, + function: with_no_trimmed_paths!(self.tcx.def_path_str(id)), + sub: CallToDeprecatedSafeFnRequiresUnsafeSub { + left: span.shrink_to_lo(), + right: span.shrink_to_hi(), + }, + }, + ); + true + } + _ => false, + } + } + fn requires_unsafe(&mut self, span: Span, kind: UnsafeOpKind) { let unsafe_op_in_unsafe_fn_allowed = self.unsafe_op_in_unsafe_fn_allowed(); match self.safety_context { @@ -101,43 +129,29 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { } SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {} SafetyContext::UnsafeFn => { - // unsafe_op_in_unsafe_fn is disallowed - kind.emit_unsafe_op_in_unsafe_fn_lint( - self.tcx, - self.hir_context, - span, - self.suggest_unsafe_block, - ); - self.suggest_unsafe_block = false; - } - SafetyContext::Safe => match kind { - // Allow calls to deprecated-safe unsafe functions if the - // caller is from an edition before 2024. - UnsafeOpKind::CallToUnsafeFunction(Some(id)) - if !span.at_least_rust_2024() - && self.tcx.has_attr(id, sym::rustc_deprecated_safe_2024) => - { - self.tcx.emit_node_span_lint( - DEPRECATED_SAFE, + let deprecated_safe_fn = self.emit_deprecated_safe_fn_call(span, &kind); + if !deprecated_safe_fn { + // unsafe_op_in_unsafe_fn is disallowed + kind.emit_unsafe_op_in_unsafe_fn_lint( + self.tcx, self.hir_context, span, - CallToDeprecatedSafeFnRequiresUnsafe { - span, - function: with_no_trimmed_paths!(self.tcx.def_path_str(id)), - sub: CallToDeprecatedSafeFnRequiresUnsafeSub { - left: span.shrink_to_lo(), - right: span.shrink_to_hi(), - }, - }, - ) + self.suggest_unsafe_block, + ); + self.suggest_unsafe_block = false; } - _ => kind.emit_requires_unsafe_err( - self.tcx, - span, - self.hir_context, - unsafe_op_in_unsafe_fn_allowed, - ), - }, + } + SafetyContext::Safe => { + let deprecated_safe_fn = self.emit_deprecated_safe_fn_call(span, &kind); + if !deprecated_safe_fn { + kind.emit_requires_unsafe_err( + self.tcx, + span, + self.hir_context, + unsafe_op_in_unsafe_fn_allowed, + ); + } + } } } @@ -456,7 +470,10 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { if self.tcx.is_mutable_static(def_id) { self.requires_unsafe(expr.span, UseOfMutableStatic); } else if self.tcx.is_foreign_item(def_id) { - self.requires_unsafe(expr.span, UseOfExternStatic); + match self.tcx.def_kind(def_id) { + DefKind::Static { safety: hir::Safety::Safe, .. } => {} + _ => self.requires_unsafe(expr.span, UseOfExternStatic), + } } } else if self.thir[arg].ty.is_unsafe_ptr() { self.requires_unsafe(expr.span, DerefOfRawPointer); @@ -597,7 +614,7 @@ enum UnsafeOpKind { use UnsafeOpKind::*; impl UnsafeOpKind { - pub fn emit_unsafe_op_in_unsafe_fn_lint( + fn emit_unsafe_op_in_unsafe_fn_lint( &self, tcx: TyCtxt<'_>, hir_id: HirId, @@ -737,7 +754,7 @@ impl UnsafeOpKind { } } - pub fn emit_requires_unsafe_err( + fn emit_requires_unsafe_err( &self, tcx: TyCtxt<'_>, span: Span, diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index d7ed4f57e59..cf324c03dc9 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -13,111 +13,111 @@ use rustc_span::Span; #[derive(LintDiagnostic)] #[diag(mir_build_unconditional_recursion)] #[help] -pub struct UnconditionalRecursion { +pub(crate) struct UnconditionalRecursion { #[label] - pub span: Span, + pub(crate) span: Span, #[label(mir_build_unconditional_recursion_call_site_label)] - pub call_sites: Vec<Span>, + pub(crate) call_sites: Vec<Span>, } #[derive(LintDiagnostic)] #[diag(mir_build_call_to_deprecated_safe_fn_requires_unsafe)] -pub struct CallToDeprecatedSafeFnRequiresUnsafe { +pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafe { #[label] - pub span: Span, - pub function: String, + pub(crate) span: Span, + pub(crate) function: String, #[subdiagnostic] - pub sub: CallToDeprecatedSafeFnRequiresUnsafeSub, + pub(crate) sub: CallToDeprecatedSafeFnRequiresUnsafeSub, } #[derive(Subdiagnostic)] #[multipart_suggestion(mir_build_suggestion, applicability = "machine-applicable")] -pub struct CallToDeprecatedSafeFnRequiresUnsafeSub { +pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafeSub { #[suggestion_part(code = "unsafe {{ ")] - pub left: Span, + pub(crate) left: Span, #[suggestion_part(code = " }}")] - pub right: Span, + pub(crate) right: Span, } #[derive(LintDiagnostic)] #[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe, code = E0133)] #[note] -pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe { +pub(crate) struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe { #[label] - pub span: Span, - pub function: String, + pub(crate) span: Span, + pub(crate) function: String, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, } #[derive(LintDiagnostic)] #[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless, code = E0133)] #[note] -pub struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless { +pub(crate) struct UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless { #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, } #[derive(LintDiagnostic)] #[diag(mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe, code = E0133)] #[note] -pub struct UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe { +pub(crate) struct UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe { #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, } #[derive(LintDiagnostic)] #[diag(mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe, code = E0133)] #[note] -pub struct UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe { +pub(crate) struct UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe { #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, } #[derive(LintDiagnostic)] #[diag(mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe, code = E0133)] #[note] -pub struct UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe { +pub(crate) struct UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe { #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, } #[derive(LintDiagnostic)] #[diag(mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe, code = E0133)] #[note] -pub struct UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe { +pub(crate) struct UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe { #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, } #[derive(LintDiagnostic)] #[diag(mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe, code = E0133)] #[note] -pub struct UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe { +pub(crate) struct UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe { #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, } #[derive(LintDiagnostic)] #[diag(mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe, code = E0133)] #[note] -pub struct UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe { +pub(crate) struct UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe { #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, } #[derive(LintDiagnostic)] @@ -126,11 +126,11 @@ pub struct UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe { code = E0133 )] #[note] -pub struct UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe { +pub(crate) struct UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe { #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, } #[derive(LintDiagnostic)] @@ -138,63 +138,63 @@ pub struct UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe { mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe, code = E0133, )] -pub struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe { +pub(crate) struct UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe { #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, } #[derive(LintDiagnostic)] #[diag(mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe, code = E0133)] #[help] -pub struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe { +pub(crate) struct UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe { #[label] - pub span: Span, - pub function: String, - pub missing_target_features: DiagArgValue, - pub missing_target_features_count: usize, + pub(crate) span: Span, + pub(crate) function: String, + pub(crate) missing_target_features: DiagArgValue, + pub(crate) missing_target_features_count: usize, #[note] - pub note: Option<()>, - pub build_target_features: DiagArgValue, - pub build_target_features_count: usize, + pub(crate) note: Option<()>, + pub(crate) build_target_features: DiagArgValue, + pub(crate) build_target_features_count: usize, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedLintNote>, } #[derive(Diagnostic)] #[diag(mir_build_call_to_unsafe_fn_requires_unsafe, code = E0133)] #[note] -pub struct CallToUnsafeFunctionRequiresUnsafe { +pub(crate) struct CallToUnsafeFunctionRequiresUnsafe { #[primary_span] #[label] - pub span: Span, - pub function: String, + pub(crate) span: Span, + pub(crate) function: String, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_call_to_unsafe_fn_requires_unsafe_nameless, code = E0133)] #[note] -pub struct CallToUnsafeFunctionRequiresUnsafeNameless { +pub(crate) struct CallToUnsafeFunctionRequiresUnsafeNameless { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] -pub struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed { +pub(crate) struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] #[label] - pub span: Span, - pub function: String, + pub(crate) span: Span, + pub(crate) function: String, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] @@ -203,45 +203,45 @@ pub struct CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed { code = E0133 )] #[note] -pub struct CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { +pub(crate) struct CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_inline_assembly_requires_unsafe, code = E0133)] #[note] -pub struct UseOfInlineAssemblyRequiresUnsafe { +pub(crate) struct UseOfInlineAssemblyRequiresUnsafe { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] -pub struct UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed { +pub(crate) struct UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_initializing_type_with_requires_unsafe, code = E0133)] #[note] -pub struct InitializingTypeWithRequiresUnsafe { +pub(crate) struct InitializingTypeWithRequiresUnsafe { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] @@ -250,111 +250,111 @@ pub struct InitializingTypeWithRequiresUnsafe { code = E0133 )] #[note] -pub struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { +pub(crate) struct InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_mutable_static_requires_unsafe, code = E0133)] #[note] -pub struct UseOfMutableStaticRequiresUnsafe { +pub(crate) struct UseOfMutableStaticRequiresUnsafe { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] -pub struct UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { +pub(crate) struct UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_extern_static_requires_unsafe, code = E0133)] #[note] -pub struct UseOfExternStaticRequiresUnsafe { +pub(crate) struct UseOfExternStaticRequiresUnsafe { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] -pub struct UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { +pub(crate) struct UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_deref_raw_pointer_requires_unsafe, code = E0133)] #[note] -pub struct DerefOfRawPointerRequiresUnsafe { +pub(crate) struct DerefOfRawPointerRequiresUnsafe { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] -pub struct DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed { +pub(crate) struct DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_union_field_requires_unsafe, code = E0133)] #[note] -pub struct AccessToUnionFieldRequiresUnsafe { +pub(crate) struct AccessToUnionFieldRequiresUnsafe { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[note] -pub struct AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { +pub(crate) struct AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_mutation_of_layout_constrained_field_requires_unsafe, code = E0133)] #[note] -pub struct MutationOfLayoutConstrainedFieldRequiresUnsafe { +pub(crate) struct MutationOfLayoutConstrainedFieldRequiresUnsafe { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] @@ -363,23 +363,23 @@ pub struct MutationOfLayoutConstrainedFieldRequiresUnsafe { code = E0133 )] #[note] -pub struct MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { +pub(crate) struct MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_borrow_of_layout_constrained_field_requires_unsafe, code = E0133)] #[note] -pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafe { +pub(crate) struct BorrowOfLayoutConstrainedFieldRequiresUnsafe { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] @@ -388,60 +388,60 @@ pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafe { code = E0133 )] #[note] -pub struct BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { +pub(crate) struct BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_call_to_fn_with_requires_unsafe, code = E0133)] #[help] -pub struct CallToFunctionWithRequiresUnsafe { +pub(crate) struct CallToFunctionWithRequiresUnsafe { #[primary_span] #[label] - pub span: Span, - pub function: String, - pub missing_target_features: DiagArgValue, - pub missing_target_features_count: usize, + pub(crate) span: Span, + pub(crate) function: String, + pub(crate) missing_target_features: DiagArgValue, + pub(crate) missing_target_features_count: usize, #[note] - pub note: Option<()>, - pub build_target_features: DiagArgValue, - pub build_target_features_count: usize, + pub(crate) note: Option<()>, + pub(crate) build_target_features: DiagArgValue, + pub(crate) build_target_features_count: usize, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Diagnostic)] #[diag(mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed, code = E0133)] #[help] -pub struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { +pub(crate) struct CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed { #[primary_span] #[label] - pub span: Span, - pub function: String, - pub missing_target_features: DiagArgValue, - pub missing_target_features_count: usize, + pub(crate) span: Span, + pub(crate) function: String, + pub(crate) missing_target_features: DiagArgValue, + pub(crate) missing_target_features_count: usize, #[note] - pub note: Option<()>, - pub build_target_features: DiagArgValue, - pub build_target_features_count: usize, + pub(crate) note: Option<()>, + pub(crate) build_target_features: DiagArgValue, + pub(crate) build_target_features_count: usize, #[subdiagnostic] - pub unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, + pub(crate) unsafe_not_inherited_note: Option<UnsafeNotInheritedNote>, } #[derive(Subdiagnostic)] #[label(mir_build_unsafe_not_inherited)] -pub struct UnsafeNotInheritedNote { +pub(crate) struct UnsafeNotInheritedNote { #[primary_span] - pub span: Span, + pub(crate) span: Span, } -pub struct UnsafeNotInheritedLintNote { - pub signature_span: Span, - pub body_span: Span, +pub(crate) struct UnsafeNotInheritedLintNote { + pub(crate) signature_span: Span, + pub(crate) body_span: Span, } impl Subdiagnostic for UnsafeNotInheritedLintNote { @@ -463,15 +463,15 @@ impl Subdiagnostic for UnsafeNotInheritedLintNote { #[derive(LintDiagnostic)] #[diag(mir_build_unused_unsafe)] -pub struct UnusedUnsafe { +pub(crate) struct UnusedUnsafe { #[label] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub enclosing: Option<UnusedUnsafeEnclosing>, + pub(crate) enclosing: Option<UnusedUnsafeEnclosing>, } #[derive(Subdiagnostic)] -pub enum UnusedUnsafeEnclosing { +pub(crate) enum UnusedUnsafeEnclosing { #[label(mir_build_unused_unsafe_enclosing_block_label)] Block { #[primary_span] @@ -480,10 +480,10 @@ pub enum UnusedUnsafeEnclosing { } pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> { - pub cx: &'m RustcPatCtxt<'p, 'tcx>, - pub scrut_span: Span, - pub braces_span: Option<Span>, - pub ty: Ty<'tcx>, + pub(crate) cx: &'m RustcPatCtxt<'p, 'tcx>, + pub(crate) scrut_span: Span, + pub(crate) braces_span: Option<Span>, + pub(crate) ty: Ty<'tcx>, } impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> { @@ -552,197 +552,197 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for NonExhaustivePatternsTypeNo #[derive(Subdiagnostic)] #[note(mir_build_non_exhaustive_match_all_arms_guarded)] -pub struct NonExhaustiveMatchAllArmsGuarded; +pub(crate) struct NonExhaustiveMatchAllArmsGuarded; #[derive(Diagnostic)] #[diag(mir_build_static_in_pattern, code = E0158)] -pub struct StaticInPattern { +pub(crate) struct StaticInPattern { #[primary_span] - pub span: Span, + pub(crate) span: Span, } #[derive(Diagnostic)] #[diag(mir_build_assoc_const_in_pattern, code = E0158)] -pub struct AssocConstInPattern { +pub(crate) struct AssocConstInPattern { #[primary_span] - pub span: Span, + pub(crate) span: Span, } #[derive(Diagnostic)] #[diag(mir_build_const_param_in_pattern, code = E0158)] -pub struct ConstParamInPattern { +pub(crate) struct ConstParamInPattern { #[primary_span] - pub span: Span, + pub(crate) span: Span, } #[derive(Diagnostic)] #[diag(mir_build_non_const_path, code = E0080)] -pub struct NonConstPath { +pub(crate) struct NonConstPath { #[primary_span] - pub span: Span, + pub(crate) span: Span, } #[derive(LintDiagnostic)] #[diag(mir_build_unreachable_pattern)] -pub struct UnreachablePattern { +pub(crate) struct UnreachablePattern { #[label] - pub span: Option<Span>, + pub(crate) span: Option<Span>, #[label(mir_build_catchall_label)] - pub catchall: Option<Span>, + pub(crate) catchall: Option<Span>, } #[derive(Diagnostic)] #[diag(mir_build_const_pattern_depends_on_generic_parameter)] -pub struct ConstPatternDependsOnGenericParameter { +pub(crate) struct ConstPatternDependsOnGenericParameter { #[primary_span] - pub span: Span, + pub(crate) span: Span, } #[derive(Diagnostic)] #[diag(mir_build_could_not_eval_const_pattern)] -pub struct CouldNotEvalConstPattern { +pub(crate) struct CouldNotEvalConstPattern { #[primary_span] - pub span: Span, + pub(crate) span: Span, } #[derive(Diagnostic)] #[diag(mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper, code = E0030)] -pub struct LowerRangeBoundMustBeLessThanOrEqualToUpper { +pub(crate) struct LowerRangeBoundMustBeLessThanOrEqualToUpper { #[primary_span] #[label] - pub span: Span, + pub(crate) span: Span, #[note(mir_build_teach_note)] - pub teach: Option<()>, + pub(crate) teach: Option<()>, } #[derive(Diagnostic)] #[diag(mir_build_literal_in_range_out_of_bounds)] -pub struct LiteralOutOfRange<'tcx> { +pub(crate) struct LiteralOutOfRange<'tcx> { #[primary_span] #[label] - pub span: Span, - pub ty: Ty<'tcx>, - pub min: i128, - pub max: u128, + pub(crate) span: Span, + pub(crate) ty: Ty<'tcx>, + pub(crate) min: i128, + pub(crate) max: u128, } #[derive(Diagnostic)] #[diag(mir_build_lower_range_bound_must_be_less_than_upper, code = E0579)] -pub struct LowerRangeBoundMustBeLessThanUpper { +pub(crate) struct LowerRangeBoundMustBeLessThanUpper { #[primary_span] - pub span: Span, + pub(crate) span: Span, } #[derive(LintDiagnostic)] #[diag(mir_build_leading_irrefutable_let_patterns)] #[note] #[help] -pub struct LeadingIrrefutableLetPatterns { - pub count: usize, +pub(crate) struct LeadingIrrefutableLetPatterns { + pub(crate) count: usize, } #[derive(LintDiagnostic)] #[diag(mir_build_trailing_irrefutable_let_patterns)] #[note] #[help] -pub struct TrailingIrrefutableLetPatterns { - pub count: usize, +pub(crate) struct TrailingIrrefutableLetPatterns { + pub(crate) count: usize, } #[derive(LintDiagnostic)] #[diag(mir_build_bindings_with_variant_name, code = E0170)] -pub struct BindingsWithVariantName { +pub(crate) struct BindingsWithVariantName { #[suggestion(code = "{ty_path}::{name}", applicability = "machine-applicable")] - pub suggestion: Option<Span>, - pub ty_path: String, - pub name: Symbol, + pub(crate) suggestion: Option<Span>, + pub(crate) ty_path: String, + pub(crate) name: Symbol, } #[derive(LintDiagnostic)] #[diag(mir_build_irrefutable_let_patterns_if_let)] #[note] #[help] -pub struct IrrefutableLetPatternsIfLet { - pub count: usize, +pub(crate) struct IrrefutableLetPatternsIfLet { + pub(crate) count: usize, } #[derive(LintDiagnostic)] #[diag(mir_build_irrefutable_let_patterns_if_let_guard)] #[note] #[help] -pub struct IrrefutableLetPatternsIfLetGuard { - pub count: usize, +pub(crate) struct IrrefutableLetPatternsIfLetGuard { + pub(crate) count: usize, } #[derive(LintDiagnostic)] #[diag(mir_build_irrefutable_let_patterns_let_else)] #[note] #[help] -pub struct IrrefutableLetPatternsLetElse { - pub count: usize, +pub(crate) struct IrrefutableLetPatternsLetElse { + pub(crate) count: usize, } #[derive(LintDiagnostic)] #[diag(mir_build_irrefutable_let_patterns_while_let)] #[note] #[help] -pub struct IrrefutableLetPatternsWhileLet { - pub count: usize, +pub(crate) struct IrrefutableLetPatternsWhileLet { + pub(crate) count: usize, } #[derive(Diagnostic)] #[diag(mir_build_borrow_of_moved_value)] -pub struct BorrowOfMovedValue<'tcx> { +pub(crate) struct BorrowOfMovedValue<'tcx> { #[primary_span] #[label] #[label(mir_build_occurs_because_label)] - pub binding_span: Span, + pub(crate) binding_span: Span, #[label(mir_build_value_borrowed_label)] - pub conflicts_ref: Vec<Span>, - pub name: Symbol, - pub ty: Ty<'tcx>, + pub(crate) conflicts_ref: Vec<Span>, + pub(crate) name: Symbol, + pub(crate) ty: Ty<'tcx>, #[suggestion(code = "ref ", applicability = "machine-applicable")] - pub suggest_borrowing: Option<Span>, + pub(crate) suggest_borrowing: Option<Span>, } #[derive(Diagnostic)] #[diag(mir_build_multiple_mut_borrows)] -pub struct MultipleMutBorrows { +pub(crate) struct MultipleMutBorrows { #[primary_span] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub occurrences: Vec<Conflict>, + pub(crate) occurrences: Vec<Conflict>, } #[derive(Diagnostic)] #[diag(mir_build_already_borrowed)] -pub struct AlreadyBorrowed { +pub(crate) struct AlreadyBorrowed { #[primary_span] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub occurrences: Vec<Conflict>, + pub(crate) occurrences: Vec<Conflict>, } #[derive(Diagnostic)] #[diag(mir_build_already_mut_borrowed)] -pub struct AlreadyMutBorrowed { +pub(crate) struct AlreadyMutBorrowed { #[primary_span] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub occurrences: Vec<Conflict>, + pub(crate) occurrences: Vec<Conflict>, } #[derive(Diagnostic)] #[diag(mir_build_moved_while_borrowed)] -pub struct MovedWhileBorrowed { +pub(crate) struct MovedWhileBorrowed { #[primary_span] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub occurrences: Vec<Conflict>, + pub(crate) occurrences: Vec<Conflict>, } #[derive(Subdiagnostic)] -pub enum Conflict { +pub(crate) enum Conflict { #[label(mir_build_mutable_borrow)] Mut { #[primary_span] @@ -765,118 +765,118 @@ pub enum Conflict { #[derive(Diagnostic)] #[diag(mir_build_union_pattern)] -pub struct UnionPattern { +pub(crate) struct UnionPattern { #[primary_span] - pub span: Span, + pub(crate) span: Span, } #[derive(Diagnostic)] #[diag(mir_build_type_not_structural)] #[note(mir_build_type_not_structural_tip)] #[note(mir_build_type_not_structural_more_info)] -pub struct TypeNotStructural<'tcx> { +pub(crate) struct TypeNotStructural<'tcx> { #[primary_span] - pub span: Span, - pub non_sm_ty: Ty<'tcx>, + pub(crate) span: Span, + pub(crate) non_sm_ty: Ty<'tcx>, } #[derive(Diagnostic)] #[diag(mir_build_non_partial_eq_match)] -pub struct TypeNotPartialEq<'tcx> { +pub(crate) struct TypeNotPartialEq<'tcx> { #[primary_span] - pub span: Span, - pub non_peq_ty: Ty<'tcx>, + pub(crate) span: Span, + pub(crate) non_peq_ty: Ty<'tcx>, } #[derive(Diagnostic)] #[diag(mir_build_invalid_pattern)] -pub struct InvalidPattern<'tcx> { +pub(crate) struct InvalidPattern<'tcx> { #[primary_span] - pub span: Span, - pub non_sm_ty: Ty<'tcx>, + pub(crate) span: Span, + pub(crate) non_sm_ty: Ty<'tcx>, } #[derive(Diagnostic)] #[diag(mir_build_unsized_pattern)] -pub struct UnsizedPattern<'tcx> { +pub(crate) struct UnsizedPattern<'tcx> { #[primary_span] - pub span: Span, - pub non_sm_ty: Ty<'tcx>, + pub(crate) span: Span, + pub(crate) non_sm_ty: Ty<'tcx>, } #[derive(Diagnostic)] #[diag(mir_build_nan_pattern)] #[note] #[help] -pub struct NaNPattern { +pub(crate) struct NaNPattern { #[primary_span] - pub span: Span, + pub(crate) span: Span, } #[derive(Diagnostic)] #[diag(mir_build_pointer_pattern)] -pub struct PointerPattern { +pub(crate) struct PointerPattern { #[primary_span] - pub span: Span, + pub(crate) span: Span, } #[derive(Diagnostic)] #[diag(mir_build_non_empty_never_pattern)] #[note] -pub struct NonEmptyNeverPattern<'tcx> { +pub(crate) struct NonEmptyNeverPattern<'tcx> { #[primary_span] #[label] - pub span: Span, - pub ty: Ty<'tcx>, + pub(crate) span: Span, + pub(crate) ty: Ty<'tcx>, } #[derive(Diagnostic)] #[diag(mir_build_exceeds_mcdc_condition_limit)] pub(crate) struct MCDCExceedsConditionLimit { #[primary_span] - pub span: Span, - pub num_conditions: usize, - pub max_conditions: usize, + pub(crate) span: Span, + pub(crate) num_conditions: usize, + pub(crate) max_conditions: usize, } #[derive(Diagnostic)] #[diag(mir_build_pattern_not_covered, code = E0005)] pub(crate) struct PatternNotCovered<'s, 'tcx> { #[primary_span] - pub span: Span, - pub origin: &'s str, + pub(crate) span: Span, + pub(crate) origin: &'s str, #[subdiagnostic] - pub uncovered: Uncovered<'tcx>, + pub(crate) uncovered: Uncovered<'tcx>, #[subdiagnostic] - pub inform: Option<Inform>, + pub(crate) inform: Option<Inform>, #[subdiagnostic] - pub interpreted_as_const: Option<InterpretedAsConst>, + pub(crate) interpreted_as_const: Option<InterpretedAsConst>, #[subdiagnostic] - pub adt_defined_here: Option<AdtDefinedHere<'tcx>>, + pub(crate) adt_defined_here: Option<AdtDefinedHere<'tcx>>, #[note(mir_build_privately_uninhabited)] - pub witness_1_is_privately_uninhabited: Option<()>, + pub(crate) witness_1_is_privately_uninhabited: Option<()>, #[note(mir_build_pattern_ty)] - pub _p: (), - pub pattern_ty: Ty<'tcx>, + pub(crate) _p: (), + pub(crate) pattern_ty: Ty<'tcx>, #[subdiagnostic] - pub let_suggestion: Option<SuggestLet>, + pub(crate) let_suggestion: Option<SuggestLet>, #[subdiagnostic] - pub misc_suggestion: Option<MiscPatternSuggestion>, + pub(crate) misc_suggestion: Option<MiscPatternSuggestion>, } #[derive(Subdiagnostic)] #[note(mir_build_inform_irrefutable)] #[note(mir_build_more_information)] -pub struct Inform; +pub(crate) struct Inform; -pub struct AdtDefinedHere<'tcx> { - pub adt_def_span: Span, - pub ty: Ty<'tcx>, - pub variants: Vec<Variant>, +pub(crate) struct AdtDefinedHere<'tcx> { + pub(crate) adt_def_span: Span, + pub(crate) ty: Ty<'tcx>, + pub(crate) variants: Vec<Variant>, } -pub struct Variant { - pub span: Span, +pub(crate) struct Variant { + pub(crate) span: Span, } impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> { @@ -903,14 +903,14 @@ impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> { applicability = "maybe-incorrect" )] #[label(mir_build_confused)] -pub struct InterpretedAsConst { +pub(crate) struct InterpretedAsConst { #[primary_span] - pub span: Span, - pub variable: String, + pub(crate) span: Span, + pub(crate) variable: String, } #[derive(Subdiagnostic)] -pub enum SuggestLet { +pub(crate) enum SuggestLet { #[multipart_suggestion(mir_build_suggest_if_let, applicability = "has-placeholders")] If { #[suggestion_part(code = "if ")] @@ -932,7 +932,7 @@ pub enum SuggestLet { } #[derive(Subdiagnostic)] -pub enum MiscPatternSuggestion { +pub(crate) enum MiscPatternSuggestion { #[suggestion( mir_build_suggest_attempted_int_lit, code = "_", @@ -946,15 +946,15 @@ pub enum MiscPatternSuggestion { #[derive(Diagnostic)] #[diag(mir_build_rustc_box_attribute_error)] -pub struct RustcBoxAttributeError { +pub(crate) struct RustcBoxAttributeError { #[primary_span] - pub span: Span, + pub(crate) span: Span, #[subdiagnostic] - pub reason: RustcBoxAttrReason, + pub(crate) reason: RustcBoxAttrReason, } #[derive(Subdiagnostic)] -pub enum RustcBoxAttrReason { +pub(crate) enum RustcBoxAttrReason { #[note(mir_build_attributes)] Attributes, #[note(mir_build_not_box)] @@ -965,13 +965,13 @@ pub enum RustcBoxAttrReason { #[derive(LintDiagnostic)] #[diag(mir_build_rust_2024_incompatible_pat)] -pub struct Rust2024IncompatiblePat { +pub(crate) struct Rust2024IncompatiblePat { #[subdiagnostic] - pub sugg: Rust2024IncompatiblePatSugg, + pub(crate) sugg: Rust2024IncompatiblePatSugg, } -pub struct Rust2024IncompatiblePatSugg { - pub suggestion: Vec<(Span, String)>, +pub(crate) struct Rust2024IncompatiblePatSugg { + pub(crate) suggestion: Vec<(Span, String)>, } impl Subdiagnostic for Rust2024IncompatiblePatSugg { diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 74600c6b12e..a1b8b578349 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -1,6 +1,4 @@ //! Construction of MIR from HIR. -//! -//! This crate also contains the match exhaustiveness and usefulness checking. #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 31bc72184ca..a98e046d4dc 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -58,11 +58,9 @@ pub(crate) fn lit_to_const<'tcx>( } (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()), (ast::LitKind::Float(n, _), ty::Float(fty)) => { - let bits = parse_float_into_scalar(*n, *fty, neg) - .ok_or_else(|| { - tcx.dcx().bug(format!("couldn't parse float literal: {:?}", lit_input.lit)) - })? - .assert_int(); + let bits = parse_float_into_scalar(*n, *fty, neg).ok_or_else(|| { + tcx.dcx().bug(format!("couldn't parse float literal: {:?}", lit_input.lit)) + })?; ty::ValTree::from_scalar_int(bits) } (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()), diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index bd66257e6b6..28f9300b97a 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -671,9 +671,9 @@ impl<'tcx> Cx<'tcx> { ExprKind::OffsetOf { container, fields } } - hir::ExprKind::ConstBlock(body) => { - let ty = self.typeck_results().node_type(body.hir_id); - let did = self.typeck_results().inline_consts[&expr.hir_id.local_id].into(); + hir::ExprKind::ConstBlock(ref anon_const) => { + let ty = self.typeck_results().node_type(anon_const.hir_id); + let did = anon_const.def_id.to_def_id(); let typeck_root_def_id = tcx.typeck_root_def_id(did); let parent_args = tcx.erase_regions(GenericArgs::identity_for_item(tcx, typeck_root_def_id)); diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index bd9e34ae80f..244ac409fd3 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -165,7 +165,7 @@ impl<'tcx> Cx<'tcx> { &'a mut self, owner_id: HirId, fn_decl: &'tcx hir::FnDecl<'tcx>, - body: &hir::Body<'tcx>, + body: &'tcx hir::Body<'tcx>, ) -> impl Iterator<Item = Param<'tcx>> + 'a { let fn_sig = self.typeck_results.liberated_fn_sigs()[owner_id]; diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 8d881713eeb..192d706bce2 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -101,9 +101,9 @@ impl<'tcx> ConstToPat<'tcx> { // level of indirection can be eliminated let have_valtree = - matches!(cv, mir::Const::Ty(c) if matches!(c.kind(), ty::ConstKind::Value(_))); + matches!(cv, mir::Const::Ty(_, c) if matches!(c.kind(), ty::ConstKind::Value(_, _))); let inlined_const_as_pat = match cv { - mir::Const::Ty(c) => match c.kind() { + mir::Const::Ty(_, c) => match c.kind() { ty::ConstKind::Param(_) | ty::ConstKind::Infer(_) | ty::ConstKind::Bound(_, _) @@ -113,8 +113,8 @@ impl<'tcx> ConstToPat<'tcx> { | ty::ConstKind::Expr(_) => { span_bug!(self.span, "unexpected const in `to_pat`: {:?}", c.kind()) } - ty::ConstKind::Value(valtree) => { - self.recur(valtree, cv.ty()).unwrap_or_else(|_: FallbackToOpaqueConst| { + ty::ConstKind::Value(ty, valtree) => { + self.recur(valtree, ty).unwrap_or_else(|_: FallbackToOpaqueConst| { Box::new(Pat { span: self.span, ty: cv.ty(), @@ -282,8 +282,7 @@ impl<'tcx> ConstToPat<'tcx> { } ty::Adt(adt_def, args) if adt_def.is_enum() => { let (&variant_index, fields) = cv.unwrap_branch().split_first().unwrap(); - let variant_index = - VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap()); + let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().to_u32()); PatKind::Variant { adt_def: *adt_def, args, @@ -336,9 +335,9 @@ impl<'tcx> ConstToPat<'tcx> { ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { // `&str` is represented as a valtree, let's keep using this // optimization for now. - ty::Str => { - PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) } - } + ty::Str => PatKind::Constant { + value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)), + }, // All other references are converted into deref patterns and then recursively // convert the dereferenced constant to a pattern that is the sub-pattern of the // deref pattern. @@ -371,8 +370,8 @@ impl<'tcx> ConstToPat<'tcx> { let v = cv.unwrap_leaf(); let is_nan = match flt { ty::FloatTy::F16 => unimplemented!("f16_f128"), - ty::FloatTy::F32 => v.try_to_f32().unwrap().is_nan(), - ty::FloatTy::F64 => v.try_to_f64().unwrap().is_nan(), + ty::FloatTy::F32 => v.to_f32().is_nan(), + ty::FloatTy::F64 => v.to_f64().is_nan(), ty::FloatTy::F128 => unimplemented!("f16_f128"), }; if is_nan { @@ -382,13 +381,15 @@ impl<'tcx> ConstToPat<'tcx> { self.saw_const_match_error.set(Some(e)); return Err(FallbackToOpaqueConst); } else { - PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) } + PatKind::Constant { + value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)), + } } } ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => { // The raw pointers we see here have been "vetted" by valtree construction to be // just integers, so we simply allow them. - PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) } + PatKind::Constant { value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)) } } ty::FnPtr(..) => { unreachable!( diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 33401cad631..158ca91fcf1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -580,7 +580,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { .tcx .const_eval_global_id_for_typeck(param_env_reveal_all, cid, span) .map(|val| match val { - Some(valtree) => mir::Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), + Some(valtree) => mir::Const::Ty(ty, ty::Const::new_value(self.tcx, valtree, ty)), None => mir::Const::Val( self.tcx .const_eval_global_id(param_env_reveal_all, cid, span) @@ -637,13 +637,15 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// Converts inline const patterns. fn lower_inline_const( &mut self, - expr: &'tcx hir::Expr<'tcx>, + block: &'tcx hir::ConstBlock, id: hir::HirId, span: Span, ) -> PatKind<'tcx> { let tcx = self.tcx; - let def_id = self.typeck_results.inline_consts[&id.local_id]; - let ty = tcx.typeck(def_id).node_type(expr.hir_id); + let def_id = block.def_id; + let body_id = block.body; + let expr = &tcx.hir().body(body_id).value; + let ty = tcx.typeck(def_id).node_type(block.hir_id); // Special case inline consts that are just literals. This is solely // a performance optimization, as we could also just go through the regular @@ -659,7 +661,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { }; if let Some(lit_input) = lit_input { match tcx.at(expr.span).lit_to_const(lit_input) { - Ok(c) => return self.const_to_pat(Const::Ty(c), id, span).kind, + Ok(c) => return self.const_to_pat(Const::Ty(ty, c), id, span).kind, // If an error occurred, ignore that it's a literal // and leave reporting the error up to const eval of // the unevaluated constant below. @@ -681,8 +683,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // but something more principled, like a trait query checking whether this can be turned into a valtree. if let Ok(Some(valtree)) = self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, span) { - let subpattern = - self.const_to_pat(Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)), id, span); + let subpattern = self.const_to_pat( + Const::Ty(ty, ty::Const::new_value(self.tcx, valtree, ty)), + id, + span, + ); PatKind::InlineConstant { subpattern, def: def_id } } else { // If that fails, convert it to an opaque constant pattern. @@ -720,10 +725,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { _ => span_bug!(expr.span, "not a literal: {:?}", expr), }; - let lit_input = - LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg }; + let ct_ty = self.typeck_results.expr_ty(expr); + let lit_input = LitToConstInput { lit: &lit.node, ty: ct_ty, neg }; match self.tcx.at(expr.span).lit_to_const(lit_input) { - Ok(constant) => self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span).kind, + Ok(constant) => { + self.const_to_pat(Const::Ty(ct_ty, constant), expr.hir_id, lit.span).kind + } Err(LitToConstError::Reported(e)) => PatKind::Error(e), Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), } diff --git a/compiler/rustc_mir_transform/src/const_debuginfo.rs b/compiler/rustc_mir_transform/src/const_debuginfo.rs deleted file mode 100644 index e4e4270c499..00000000000 --- a/compiler/rustc_mir_transform/src/const_debuginfo.rs +++ /dev/null @@ -1,102 +0,0 @@ -//! Finds locals which are assigned once to a const and unused except for debuginfo and converts -//! their debuginfo to use the const directly, allowing the local to be removed. - -use rustc_middle::{ - mir::{ - visit::{PlaceContext, Visitor}, - Body, ConstOperand, Local, Location, Operand, Rvalue, StatementKind, VarDebugInfoContents, - }, - ty::TyCtxt, -}; - -use crate::MirPass; -use rustc_index::{bit_set::BitSet, IndexVec}; - -pub struct ConstDebugInfo; - -impl<'tcx> MirPass<'tcx> for ConstDebugInfo { - fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() > 0 - } - - fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - trace!("running ConstDebugInfo on {:?}", body.source); - - for (local, constant) in find_optimization_opportunities(body) { - for debuginfo in &mut body.var_debug_info { - if let VarDebugInfoContents::Place(p) = debuginfo.value { - if p.local == local && p.projection.is_empty() { - trace!( - "changing debug info for {:?} from place {:?} to constant {:?}", - debuginfo.name, - p, - constant - ); - debuginfo.value = VarDebugInfoContents::Const(constant); - } - } - } - } - } -} - -struct LocalUseVisitor { - local_mutating_uses: IndexVec<Local, u8>, - local_assignment_locations: IndexVec<Local, Option<Location>>, -} - -fn find_optimization_opportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, ConstOperand<'tcx>)> { - let mut visitor = LocalUseVisitor { - local_mutating_uses: IndexVec::from_elem(0, &body.local_decls), - local_assignment_locations: IndexVec::from_elem(None, &body.local_decls), - }; - - visitor.visit_body(body); - - let mut locals_to_debuginfo = BitSet::new_empty(body.local_decls.len()); - for debuginfo in &body.var_debug_info { - if let VarDebugInfoContents::Place(p) = debuginfo.value - && let Some(l) = p.as_local() - { - locals_to_debuginfo.insert(l); - } - } - - let mut eligible_locals = Vec::new(); - for (local, mutating_uses) in visitor.local_mutating_uses.drain_enumerated(..) { - if mutating_uses != 1 || !locals_to_debuginfo.contains(local) { - continue; - } - - if let Some(location) = visitor.local_assignment_locations[local] { - let bb = &body[location.block]; - - // The value is assigned as the result of a call, not a constant - if bb.statements.len() == location.statement_index { - continue; - } - - if let StatementKind::Assign(box (p, Rvalue::Use(Operand::Constant(box c)))) = - &bb.statements[location.statement_index].kind - { - if let Some(local) = p.as_local() { - eligible_locals.push((local, *c)); - } - } - } - } - - eligible_locals -} - -impl Visitor<'_> for LocalUseVisitor { - fn visit_local(&mut self, local: Local, context: PlaceContext, location: Location) { - if context.is_mutating_use() { - self.local_mutating_uses[local] = self.local_mutating_uses[local].saturating_add(1); - - if context.is_place_assignment() { - self.local_assignment_locations[local] = Some(location); - } - } - } -} diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index ade2ac0080e..84512e81637 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1608,7 +1608,7 @@ fn check_field_tys_sized<'tcx>( let infcx = tcx.infer_ctxt().ignoring_regions().build(); let param_env = tcx.param_env(def_id); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); for field_ty in &coroutine_layout.field_tys { ocx.register_bound( ObligationCause::new( diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index f2f76ac70c2..743f1cc24be 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -20,37 +20,31 @@ pub(super) fn extract_refined_covspans( basic_coverage_blocks: &CoverageGraph, code_mappings: &mut impl Extend<mappings::CodeMapping>, ) { - let sorted_spans = + let sorted_span_buckets = from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks); - let coverage_spans = SpansRefiner::refine_sorted_spans(sorted_spans); - code_mappings.extend(coverage_spans.into_iter().map(|RefinedCovspan { bcb, span, .. }| { - // Each span produced by the generator represents an ordinary code region. - mappings::CodeMapping { span, bcb } - })); + for bucket in sorted_span_buckets { + let refined_spans = SpansRefiner::refine_sorted_spans(bucket); + code_mappings.extend(refined_spans.into_iter().map(|RefinedCovspan { span, bcb }| { + // Each span produced by the refiner represents an ordinary code region. + mappings::CodeMapping { span, bcb } + })); + } } #[derive(Debug)] struct CurrCovspan { span: Span, bcb: BasicCoverageBlock, - is_hole: bool, } impl CurrCovspan { - fn new(span: Span, bcb: BasicCoverageBlock, is_hole: bool) -> Self { - Self { span, bcb, is_hole } + fn new(span: Span, bcb: BasicCoverageBlock) -> Self { + Self { span, bcb } } fn into_prev(self) -> PrevCovspan { - let Self { span, bcb, is_hole } = self; - PrevCovspan { span, bcb, merged_spans: vec![span], is_hole } - } - - fn into_refined(self) -> RefinedCovspan { - // This is only called in cases where `curr` is a hole span that has - // been carved out of `prev`. - debug_assert!(self.is_hole); - self.into_prev().into_refined() + let Self { span, bcb } = self; + PrevCovspan { span, bcb, merged_spans: vec![span] } } } @@ -61,12 +55,11 @@ struct PrevCovspan { /// List of all the original spans from MIR that have been merged into this /// span. Mainly used to precisely skip over gaps when truncating a span. merged_spans: Vec<Span>, - is_hole: bool, } impl PrevCovspan { fn is_mergeable(&self, other: &CurrCovspan) -> bool { - self.bcb == other.bcb && !self.is_hole && !other.is_hole + self.bcb == other.bcb } fn merge_from(&mut self, other: &CurrCovspan) { @@ -84,14 +77,9 @@ impl PrevCovspan { if self.merged_spans.is_empty() { None } else { Some(self.into_refined()) } } - fn refined_copy(&self) -> RefinedCovspan { - let &Self { span, bcb, merged_spans: _, is_hole } = self; - RefinedCovspan { span, bcb, is_hole } - } - fn into_refined(self) -> RefinedCovspan { - // Even though we consume self, we can just reuse the copying impl. - self.refined_copy() + let Self { span, bcb, merged_spans: _ } = self; + RefinedCovspan { span, bcb } } } @@ -99,12 +87,11 @@ impl PrevCovspan { struct RefinedCovspan { span: Span, bcb: BasicCoverageBlock, - is_hole: bool, } impl RefinedCovspan { fn is_mergeable(&self, other: &Self) -> bool { - self.bcb == other.bcb && !self.is_hole && !other.is_hole + self.bcb == other.bcb } fn merge_from(&mut self, other: &Self) { @@ -119,8 +106,6 @@ impl RefinedCovspan { /// * Remove duplicate source code coverage regions /// * Merge spans that represent continuous (both in source code and control flow), non-branching /// execution -/// * Carve out (leave uncovered) any "hole" spans that need to be left blank -/// (e.g. closures that will be counted by their own MIR body) struct SpansRefiner { /// The initial set of coverage spans, sorted by `Span` (`lo` and `hi`) and by relative /// dominance between the `BasicCoverageBlock`s of equal `Span`s. @@ -181,13 +166,6 @@ impl SpansRefiner { ); let prev = self.take_prev().into_refined(); self.refined_spans.push(prev); - } else if prev.is_hole { - // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the - // next iter - debug!(?prev, "prev (a hole) overlaps curr, so discarding curr"); - self.take_curr(); // Discards curr. - } else if curr.is_hole { - self.carve_out_span_for_hole(); } else { self.cutoff_prev_at_overlapping_curr(); } @@ -211,9 +189,6 @@ impl SpansRefiner { } }); - // Discard hole spans, since their purpose was to carve out chunks from - // other spans, but we don't want the holes themselves in the final mappings. - self.refined_spans.retain(|covspan| !covspan.is_hole); self.refined_spans } @@ -249,50 +224,17 @@ impl SpansRefiner { if let Some(curr) = self.some_curr.take() { self.some_prev = Some(curr.into_prev()); } - while let Some(curr) = self.sorted_spans_iter.next() { - debug!("FOR curr={:?}", curr); - if let Some(prev) = &self.some_prev - && prev.span.lo() > curr.span.lo() - { - // Skip curr because prev has already advanced beyond the end of curr. - // This can only happen if a prior iteration updated `prev` to skip past - // a region of code, such as skipping past a hole. - debug!(?prev, "prev.span starts after curr.span, so curr will be dropped"); - } else { - self.some_curr = Some(CurrCovspan::new(curr.span, curr.bcb, curr.is_hole)); - return true; + if let Some(SpanFromMir { span, bcb, .. }) = self.sorted_spans_iter.next() { + // This code only sees sorted spans after hole-carving, so there should + // be no way for `curr` to start before `prev`. + if let Some(prev) = &self.some_prev { + debug_assert!(prev.span.lo() <= span.lo()); } - } - false - } - - /// If `prev`s span extends left of the hole (`curr`), carve out the hole's span from - /// `prev`'s span. Add the portion of the span to the left of the hole; and if the span - /// extends to the right of the hole, update `prev` to that portion of the span. - fn carve_out_span_for_hole(&mut self) { - let prev = self.prev(); - let curr = self.curr(); - - let left_cutoff = curr.span.lo(); - let right_cutoff = curr.span.hi(); - let has_pre_hole_span = prev.span.lo() < right_cutoff; - let has_post_hole_span = prev.span.hi() > right_cutoff; - - if has_pre_hole_span { - let mut pre_hole = prev.refined_copy(); - pre_hole.span = pre_hole.span.with_hi(left_cutoff); - debug!(?pre_hole, "prev overlaps a hole; adding pre-hole span"); - self.refined_spans.push(pre_hole); - } - - if has_post_hole_span { - // Mutate `prev.span` to start after the hole (and discard curr). - self.prev_mut().span = self.prev().span.with_lo(right_cutoff); - debug!(prev=?self.prev(), "mutated prev to start after the hole"); - - // Prevent this curr from becoming prev. - let hole_covspan = self.take_curr().into_refined(); - self.refined_spans.push(hole_covspan); // since self.prev() was already updated + self.some_curr = Some(CurrCovspan::new(span, bcb)); + debug!(?self.some_prev, ?self.some_curr, "next_coverage_span"); + true + } else { + false } } diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index d1727a94a35..b1f71035dde 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -1,3 +1,5 @@ +use std::collections::VecDeque; + use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; @@ -17,23 +19,34 @@ use crate::coverage::ExtractedHirInfo; /// spans, each associated with a node in the coverage graph (BCB) and possibly /// other metadata. /// -/// The returned spans are sorted in a specific order that is expected by the -/// subsequent span-refinement step. +/// The returned spans are divided into one or more buckets, such that: +/// - The spans in each bucket are strictly after all spans in previous buckets, +/// and strictly before all spans in subsequent buckets. +/// - The contents of each bucket are also sorted, in a specific order that is +/// expected by the subsequent span-refinement step. pub(super) fn mir_to_initial_sorted_coverage_spans( mir_body: &mir::Body<'_>, hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, -) -> Vec<SpanFromMir> { +) -> Vec<Vec<SpanFromMir>> { let &ExtractedHirInfo { body_span, .. } = hir_info; let mut initial_spans = vec![]; + let mut holes = vec![]; for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() { - initial_spans.extend(bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data)); + bcb_to_initial_coverage_spans( + mir_body, + body_span, + bcb, + bcb_data, + &mut initial_spans, + &mut holes, + ); } // Only add the signature span if we found at least one span in the body. - if !initial_spans.is_empty() { + if !initial_spans.is_empty() || !holes.is_empty() { // If there is no usable signature span, add a fake one (before refinement) // to avoid an ugly gap between the body start and the first real span. // FIXME: Find a more principled way to solve this problem. @@ -45,29 +58,82 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( remove_unwanted_macro_spans(&mut initial_spans); split_visible_macro_spans(&mut initial_spans); - initial_spans.sort_by(|a, b| { - // First sort by span start. - Ord::cmp(&a.span.lo(), &b.span.lo()) - // If span starts are the same, sort by span end in reverse order. - // This ensures that if spans A and B are adjacent in the list, - // and they overlap but are not equal, then either: - // - Span A extends further left, or - // - Both have the same start and span A extends further right - .then_with(|| Ord::cmp(&a.span.hi(), &b.span.hi()).reverse()) - // If two spans have the same lo & hi, put hole spans first, - // as they take precedence over non-hole spans. - .then_with(|| Ord::cmp(&a.is_hole, &b.is_hole).reverse()) + let compare_covspans = |a: &SpanFromMir, b: &SpanFromMir| { + compare_spans(a.span, b.span) // After deduplication, we want to keep only the most-dominated BCB. .then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb).reverse()) - }); + }; + initial_spans.sort_by(compare_covspans); - // Among covspans with the same span, keep only one. Hole spans take - // precedence, otherwise keep the one with the most-dominated BCB. + // Among covspans with the same span, keep only one, + // preferring the one with the most-dominated BCB. // (Ideally we should try to preserve _all_ non-dominating BCBs, but that // requires a lot more complexity in the span refiner, for little benefit.) initial_spans.dedup_by(|b, a| a.span.source_equal(b.span)); - initial_spans + // Sort the holes, and merge overlapping/adjacent holes. + holes.sort_by(|a, b| compare_spans(a.span, b.span)); + holes.dedup_by(|b, a| a.merge_if_overlapping_or_adjacent(b)); + + // Now we're ready to start carving holes out of the initial coverage spans, + // and grouping them in buckets separated by the holes. + + let mut initial_spans = VecDeque::from(initial_spans); + let mut fragments: Vec<SpanFromMir> = vec![]; + + // For each hole: + // - Identify the spans that are entirely or partly before the hole. + // - Put those spans in a corresponding bucket, truncated to the start of the hole. + // - If one of those spans also extends after the hole, put the rest of it + // in a "fragments" vector that is processed by the next hole. + let mut buckets = (0..holes.len()).map(|_| vec![]).collect::<Vec<_>>(); + for (hole, bucket) in holes.iter().zip(&mut buckets) { + let fragments_from_prev = std::mem::take(&mut fragments); + + // Only inspect spans that precede or overlap this hole, + // leaving the rest to be inspected by later holes. + // (This relies on the spans and holes both being sorted.) + let relevant_initial_spans = + drain_front_while(&mut initial_spans, |c| c.span.lo() < hole.span.hi()); + + for covspan in fragments_from_prev.into_iter().chain(relevant_initial_spans) { + let (before, after) = covspan.split_around_hole_span(hole.span); + bucket.extend(before); + fragments.extend(after); + } + } + + // After finding the spans before each hole, any remaining fragments/spans + // form their own final bucket, after the final hole. + // (If there were no holes, this will just be all of the initial spans.) + fragments.extend(initial_spans); + buckets.push(fragments); + + // Make sure each individual bucket is still internally sorted. + for bucket in &mut buckets { + bucket.sort_by(compare_covspans); + } + buckets +} + +fn compare_spans(a: Span, b: Span) -> std::cmp::Ordering { + // First sort by span start. + Ord::cmp(&a.lo(), &b.lo()) + // If span starts are the same, sort by span end in reverse order. + // This ensures that if spans A and B are adjacent in the list, + // and they overlap but are not equal, then either: + // - Span A extends further left, or + // - Both have the same start and span A extends further right + .then_with(|| Ord::cmp(&a.hi(), &b.hi()).reverse()) +} + +/// Similar to `.drain(..)`, but stops just before it would remove an item not +/// satisfying the predicate. +fn drain_front_while<'a, T>( + queue: &'a mut VecDeque<T>, + mut pred_fn: impl FnMut(&T) -> bool, +) -> impl Iterator<Item = T> + Captures<'a> { + std::iter::from_fn(move || if pred_fn(queue.front()?) { queue.pop_front() } else { None }) } /// Macros that expand into branches (e.g. `assert!`, `trace!`) tend to generate @@ -80,8 +146,8 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( fn remove_unwanted_macro_spans(initial_spans: &mut Vec<SpanFromMir>) { let mut seen_macro_spans = FxHashSet::default(); initial_spans.retain(|covspan| { - // Ignore (retain) hole spans and non-macro-expansion spans. - if covspan.is_hole || covspan.visible_macro.is_none() { + // Ignore (retain) non-macro-expansion spans. + if covspan.visible_macro.is_none() { return true; } @@ -98,10 +164,6 @@ fn split_visible_macro_spans(initial_spans: &mut Vec<SpanFromMir>) { let mut extra_spans = vec![]; initial_spans.retain(|covspan| { - if covspan.is_hole { - return true; - } - let Some(visible_macro) = covspan.visible_macro else { return true }; let split_len = visible_macro.as_str().len() as u32 + 1; @@ -114,9 +176,8 @@ fn split_visible_macro_spans(initial_spans: &mut Vec<SpanFromMir>) { return true; } - assert!(!covspan.is_hole); - extra_spans.push(SpanFromMir::new(before, covspan.visible_macro, covspan.bcb, false)); - extra_spans.push(SpanFromMir::new(after, covspan.visible_macro, covspan.bcb, false)); + extra_spans.push(SpanFromMir::new(before, covspan.visible_macro, covspan.bcb)); + extra_spans.push(SpanFromMir::new(after, covspan.visible_macro, covspan.bcb)); false // Discard the original covspan that we just split. }); @@ -135,8 +196,10 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( body_span: Span, bcb: BasicCoverageBlock, bcb_data: &'a BasicCoverageBlockData, -) -> impl Iterator<Item = SpanFromMir> + Captures<'a> + Captures<'tcx> { - bcb_data.basic_blocks.iter().flat_map(move |&bb| { + initial_covspans: &mut Vec<SpanFromMir>, + holes: &mut Vec<Hole>, +) { + for &bb in &bcb_data.basic_blocks { let data = &mir_body[bb]; let unexpand = move |expn_span| { @@ -146,24 +209,32 @@ fn bcb_to_initial_coverage_spans<'a, 'tcx>( .filter(|(span, _)| !span.source_equal(body_span)) }; - let statement_spans = data.statements.iter().filter_map(move |statement| { + let mut extract_statement_span = |statement| { let expn_span = filtered_statement_span(statement)?; let (span, visible_macro) = unexpand(expn_span)?; // A statement that looks like the assignment of a closure expression // is treated as a "hole" span, to be carved out of other spans. - Some(SpanFromMir::new(span, visible_macro, bcb, is_closure_like(statement))) - }); + if is_closure_like(statement) { + holes.push(Hole { span }); + } else { + initial_covspans.push(SpanFromMir::new(span, visible_macro, bcb)); + } + Some(()) + }; + for statement in data.statements.iter() { + extract_statement_span(statement); + } - let terminator_span = Some(data.terminator()).into_iter().filter_map(move |terminator| { + let mut extract_terminator_span = |terminator| { let expn_span = filtered_terminator_span(terminator)?; let (span, visible_macro) = unexpand(expn_span)?; - Some(SpanFromMir::new(span, visible_macro, bcb, false)) - }); - - statement_spans.chain(terminator_span) - }) + initial_covspans.push(SpanFromMir::new(span, visible_macro, bcb)); + Some(()) + }; + extract_terminator_span(data.terminator()); + } } fn is_closure_like(statement: &Statement<'_>) -> bool { @@ -331,6 +402,22 @@ fn unexpand_into_body_span_with_prev( } #[derive(Debug)] +struct Hole { + span: Span, +} + +impl Hole { + fn merge_if_overlapping_or_adjacent(&mut self, other: &mut Self) -> bool { + if !self.span.overlaps_or_adjacent(other.span) { + return false; + } + + self.span = self.span.to(other.span); + true + } +} + +#[derive(Debug)] pub(super) struct SpanFromMir { /// A span that has been extracted from MIR and then "un-expanded" back to /// within the current function's `body_span`. After various intermediate @@ -342,23 +429,30 @@ pub(super) struct SpanFromMir { pub(super) span: Span, visible_macro: Option<Symbol>, pub(super) bcb: BasicCoverageBlock, - /// If true, this covspan represents a "hole" that should be carved out - /// from other spans, e.g. because it represents a closure expression that - /// will be instrumented separately as its own function. - pub(super) is_hole: bool, } impl SpanFromMir { fn for_fn_sig(fn_sig_span: Span) -> Self { - Self::new(fn_sig_span, None, START_BCB, false) + Self::new(fn_sig_span, None, START_BCB) + } + + fn new(span: Span, visible_macro: Option<Symbol>, bcb: BasicCoverageBlock) -> Self { + Self { span, visible_macro, bcb } } - fn new( - span: Span, - visible_macro: Option<Symbol>, - bcb: BasicCoverageBlock, - is_hole: bool, - ) -> Self { - Self { span, visible_macro, bcb, is_hole } + /// Splits this span into 0-2 parts: + /// - The part that is strictly before the hole span, if any. + /// - The part that is strictly after the hole span, if any. + fn split_around_hole_span(&self, hole_span: Span) -> (Option<Self>, Option<Self>) { + let before = try { + let span = self.span.trim_end(hole_span)?; + Self { span, ..*self } + }; + let after = try { + let span = self.span.trim_start(hole_span)?; + Self { span, ..*self } + }; + + (before, after) } } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index e88b727a21e..0fd85eb345d 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -10,7 +10,7 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::{InterpResult, Scalar}; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_mir_dataflow::value_analysis::{ Map, PlaceIndex, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace, @@ -203,7 +203,8 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { && 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.kind() - && let Some(len) = Const::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env) + && let Some(len) = Const::Ty(self.tcx.types.usize, *len) + .try_eval_scalar_int(self.tcx, self.param_env) { state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map()); } @@ -221,7 +222,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { Rvalue::Len(place) => { let place_ty = place.ty(self.local_decls, self.tcx); if let ty::Array(_, len) = place_ty.ty.kind() { - Const::Ty(*len) + Const::Ty(self.tcx.types.usize, *len) .try_eval_scalar(self.tcx, self.param_env) .map_or(FlatSet::Top, FlatSet::Elem) } else if let [ProjectionElem::Deref] = place.projection[..] { @@ -284,9 +285,11 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { let val = match null_op { NullOp::SizeOf if layout.is_sized() => layout.size.bytes(), NullOp::AlignOf if layout.is_sized() => layout.align.abi.bytes(), - NullOp::OffsetOf(fields) => { - layout.offset_of_subfield(&self.ecx, fields.iter()).bytes() - } + NullOp::OffsetOf(fields) => self + .ecx + .tcx + .offset_of_subfield(self.ecx.param_env(), layout, fields.iter()) + .bytes(), _ => return ValueOrPlace::Value(FlatSet::Top), }; FlatSet::Elem(Scalar::from_target_usize(val, &self.tcx)) @@ -323,7 +326,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { // This allows the set of visited edges to grow monotonically with the lattice. FlatSet::Bottom => TerminatorEdges::None, FlatSet::Elem(scalar) => { - let choice = scalar.assert_bits(scalar.size()); + let choice = scalar.assert_scalar_int().to_bits_unchecked(); TerminatorEdges::Single(targets.target_for_value(choice)) } FlatSet::Top => TerminatorEdges::SwitchInt { discr, targets }, @@ -606,7 +609,7 @@ fn propagatable_scalar( map: &Map, ) -> Option<Scalar> { if let FlatSet::Elem(value) = state.get_idx(place, map) - && value.try_to_int().is_ok() + && value.try_to_scalar_int().is_ok() { // Do not attempt to propagate pointers, as we may fail to preserve their identity. Some(value) @@ -667,7 +670,7 @@ fn try_write_constant<'tcx>( let FlatSet::Elem(Scalar::Int(discr)) = state.get_idx(discr, map) else { throw_machine_stop_str!("discriminant with provenance") }; - let discr_bits = discr.assert_bits(discr.size()); + let discr_bits = discr.to_bits(discr.size()); let Some((variant, _)) = def.discriminants(*ecx.tcx).find(|(_, var)| discr_bits == var.val) else { throw_machine_stop_str!("illegal discriminant for enum") }; diff --git a/compiler/rustc_mir_transform/src/dump_mir.rs b/compiler/rustc_mir_transform/src/dump_mir.rs index 13841be494c..3b71cf02c1a 100644 --- a/compiler/rustc_mir_transform/src/dump_mir.rs +++ b/compiler/rustc_mir_transform/src/dump_mir.rs @@ -28,6 +28,9 @@ pub fn emit_mir(tcx: TyCtxt<'_>) -> io::Result<()> { OutFileName::Real(path) => { let mut f = io::BufWriter::new(File::create(&path)?); write_mir_pretty(tcx, None, &mut f)?; + if tcx.sess.opts.json_artifact_notifications { + tcx.dcx().emit_artifact_notification(&path, "mir"); + } } } Ok(()) diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs index 03d952abad1..665b2260294 100644 --- a/compiler/rustc_mir_transform/src/elaborate_drops.rs +++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs @@ -34,14 +34,14 @@ use std::fmt; /// /// ```text // fn drop_term<T>(t: &mut T) { -// mir!( +// mir! { // { // Drop(*t, exit) // } // exit = { // Return() // } -// ) +// } // } /// ``` pub struct ElaborateDrops; diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index fadb5edefdf..121a3b99a39 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -83,8 +83,8 @@ //! that contain `AllocId`s. use rustc_const_eval::const_eval::DummyMachine; -use rustc_const_eval::interpret::{intern_const_alloc_for_constprop, MemoryKind}; -use rustc_const_eval::interpret::{ImmTy, InterpCx, OpTy, Projectable, Scalar}; +use rustc_const_eval::interpret::{intern_const_alloc_for_constprop, MemPlaceMeta, MemoryKind}; +use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable, Scalar}; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::graph::dominators::Dominators; use rustc_hir::def::DefKind; @@ -95,11 +95,11 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::GlobalAlloc; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; -use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::DefId; use rustc_span::DUMMY_SP; -use rustc_target::abi::{self, Abi, Size, VariantIdx, FIRST_VARIANT}; +use rustc_target::abi::{self, Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT}; use smallvec::SmallVec; use std::borrow::Cow; @@ -177,6 +177,12 @@ enum AggregateTy<'tcx> { Array, Tuple, Def(DefId, ty::GenericArgsRef<'tcx>), + RawPtr { + /// Needed for cast propagation. + data_pointer_ty: Ty<'tcx>, + /// The data pointer can be anything thin, so doesn't determine the output. + output_pointer_ty: Ty<'tcx>, + }, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -223,7 +229,6 @@ enum Value<'tcx> { NullaryOp(NullOp<'tcx>, Ty<'tcx>), UnaryOp(UnOp, VnIndex), BinaryOp(BinOp, VnIndex, VnIndex), - CheckedBinaryOp(BinOp, VnIndex, VnIndex), // FIXME get rid of this, work like MIR instead Cast { kind: CastKind, value: VnIndex, @@ -386,11 +391,22 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { AggregateTy::Def(def_id, args) => { self.tcx.type_of(def_id).instantiate(self.tcx, args) } + AggregateTy::RawPtr { output_pointer_ty, .. } => output_pointer_ty, }; let variant = if ty.is_enum() { Some(variant) } else { None }; let ty = self.ecx.layout_of(ty).ok()?; if ty.is_zst() { ImmTy::uninit(ty).into() + } else if matches!(kind, AggregateTy::RawPtr { .. }) { + // Pointers don't have fields, so don't `project_field` them. + let data = self.ecx.read_pointer(fields[0]).ok()?; + let meta = if fields[1].layout.is_zst() { + MemPlaceMeta::None + } else { + MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).ok()?) + }; + let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx); + ImmTy::from_immediate(ptr_imm, ty).into() } else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { let dest = self.ecx.allocate(ty, MemoryKind::Stack).ok()?; let variant_dest = if let Some(variant) = variant { @@ -472,7 +488,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let slice = self.evaluated[slice].as_ref()?; let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap(); let len = slice.len(&self.ecx).ok()?; - let imm = ImmTy::try_from_uint(len, usize_layout)?; + let imm = ImmTy::from_uint(len, usize_layout); imm.into() } NullaryOp(null_op, ty) => { @@ -485,13 +501,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let val = match null_op { NullOp::SizeOf => layout.size.bytes(), NullOp::AlignOf => layout.align.abi.bytes(), - NullOp::OffsetOf(fields) => { - layout.offset_of_subfield(&self.ecx, fields.iter()).bytes() - } + NullOp::OffsetOf(fields) => self + .ecx + .tcx + .offset_of_subfield(self.ecx.param_env(), layout, fields.iter()) + .bytes(), NullOp::UbChecks => return None, }; let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap(); - let imm = ImmTy::try_from_uint(val, usize_layout)?; + let imm = ImmTy::from_uint(val, usize_layout); imm.into() } UnaryOp(un_op, operand) => { @@ -508,17 +526,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let val = self.ecx.binary_op(bin_op, &lhs, &rhs).ok()?; val.into() } - CheckedBinaryOp(bin_op, lhs, rhs) => { - let lhs = self.evaluated[lhs].as_ref()?; - let lhs = self.ecx.read_immediate(lhs).ok()?; - let rhs = self.evaluated[rhs].as_ref()?; - let rhs = self.ecx.read_immediate(rhs).ok()?; - let val = self - .ecx - .binary_op(bin_op.wrapping_to_overflowing().unwrap(), &lhs, &rhs) - .ok()?; - val.into() - } Cast { kind, value, from: _, to } => match kind { CastKind::IntToInt | CastKind::IntToFloat => { let value = self.evaluated[value].as_ref()?; @@ -829,17 +836,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let lhs = lhs?; let rhs = rhs?; - if let Some(op) = op.overflowing_to_wrapping() { - if let Some(value) = self.simplify_binary(op, true, ty, lhs, rhs) { - return Some(value); - } - Value::CheckedBinaryOp(op, lhs, rhs) - } else { - if let Some(value) = self.simplify_binary(op, false, ty, lhs, rhs) { - return Some(value); - } - Value::BinaryOp(op, lhs, rhs) + if let Some(value) = self.simplify_binary(op, ty, lhs, rhs) { + return Some(value); } + Value::BinaryOp(op, lhs, rhs) } Rvalue::UnaryOp(op, ref mut arg) => { let arg = self.simplify_operand(arg, location)?; @@ -881,10 +881,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { rvalue: &mut Rvalue<'tcx>, location: Location, ) -> Option<VnIndex> { - let Rvalue::Aggregate(box ref kind, ref mut fields) = *rvalue else { bug!() }; + let Rvalue::Aggregate(box ref kind, ref mut field_ops) = *rvalue else { bug!() }; let tcx = self.tcx; - if fields.is_empty() { + if field_ops.is_empty() { let is_zst = match *kind { AggregateKind::Array(..) | AggregateKind::Tuple @@ -903,13 +903,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } - let (ty, variant_index) = match *kind { + let (mut ty, variant_index) = match *kind { AggregateKind::Array(..) => { - assert!(!fields.is_empty()); + assert!(!field_ops.is_empty()); (AggregateTy::Array, FIRST_VARIANT) } AggregateKind::Tuple => { - assert!(!fields.is_empty()); + assert!(!field_ops.is_empty()); (AggregateTy::Tuple, FIRST_VARIANT) } AggregateKind::Closure(did, args) @@ -920,15 +920,49 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } // Do not track unions. AggregateKind::Adt(_, _, _, _, Some(_)) => return None, - // FIXME: Do the extra work to GVN `from_raw_parts` - AggregateKind::RawPtr(..) => return None, + AggregateKind::RawPtr(pointee_ty, mtbl) => { + assert_eq!(field_ops.len(), 2); + let data_pointer_ty = field_ops[FieldIdx::ZERO].ty(self.local_decls, self.tcx); + let output_pointer_ty = Ty::new_ptr(self.tcx, pointee_ty, mtbl); + (AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty }, FIRST_VARIANT) + } }; - let fields: Option<Vec<_>> = fields + let fields: Option<Vec<_>> = field_ops .iter_mut() .map(|op| self.simplify_operand(op, location).or_else(|| self.new_opaque())) .collect(); - let fields = fields?; + let mut fields = fields?; + + if let AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty } = &mut ty { + let mut was_updated = false; + + // Any thin pointer of matching mutability is fine as the data pointer. + while let Value::Cast { + kind: CastKind::PtrToPtr, + value: cast_value, + from: cast_from, + to: _, + } = self.get(fields[0]) + && let ty::RawPtr(from_pointee_ty, from_mtbl) = cast_from.kind() + && let ty::RawPtr(_, output_mtbl) = output_pointer_ty.kind() + && from_mtbl == output_mtbl + && from_pointee_ty.is_sized(self.tcx, self.param_env) + { + fields[0] = *cast_value; + *data_pointer_ty = *cast_from; + was_updated = true; + } + + if was_updated { + if let Some(const_) = self.try_as_constant(fields[0]) { + field_ops[FieldIdx::ZERO] = Operand::Constant(Box::new(const_)); + } else if let Some(local) = self.try_as_local(fields[0], location) { + field_ops[FieldIdx::ZERO] = Operand::Copy(Place::from(local)); + self.reused_locals.insert(local); + } + } + } if let AggregateTy::Array = ty && fields.len() > 4 @@ -960,6 +994,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { (UnOp::Not, Value::BinaryOp(BinOp::Ne, lhs, rhs)) => { Value::BinaryOp(BinOp::Eq, *lhs, *rhs) } + (UnOp::PtrMetadata, Value::Aggregate(AggregateTy::RawPtr { .. }, _, fields)) => { + return Some(fields[1]); + } _ => return None, }; @@ -970,7 +1007,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { fn simplify_binary( &mut self, op: BinOp, - checked: bool, lhs_ty: Ty<'tcx>, lhs: VnIndex, rhs: VnIndex, @@ -999,22 +1035,39 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { use Either::{Left, Right}; let a = as_bits(lhs).map_or(Right(lhs), Left); let b = as_bits(rhs).map_or(Right(rhs), Left); + let result = match (op, a, b) { // Neutral elements. - (BinOp::Add | BinOp::BitOr | BinOp::BitXor, Left(0), Right(p)) + ( + BinOp::Add + | BinOp::AddWithOverflow + | BinOp::AddUnchecked + | BinOp::BitOr + | BinOp::BitXor, + Left(0), + Right(p), + ) | ( BinOp::Add + | BinOp::AddWithOverflow + | BinOp::AddUnchecked | BinOp::BitOr | BinOp::BitXor | BinOp::Sub + | BinOp::SubWithOverflow + | BinOp::SubUnchecked | BinOp::Offset | BinOp::Shl | BinOp::Shr, Right(p), Left(0), ) - | (BinOp::Mul, Left(1), Right(p)) - | (BinOp::Mul | BinOp::Div, Right(p), Left(1)) => p, + | (BinOp::Mul | BinOp::MulWithOverflow | BinOp::MulUnchecked, Left(1), Right(p)) + | ( + BinOp::Mul | BinOp::MulWithOverflow | BinOp::MulUnchecked | BinOp::Div, + Right(p), + Left(1), + ) => p, // Attempt to simplify `x & ALL_ONES` to `x`, with `ALL_ONES` depending on type size. (BinOp::BitAnd, Right(p), Left(ones)) | (BinOp::BitAnd, Left(ones), Right(p)) if ones == layout.size.truncate(u128::MAX) @@ -1023,10 +1076,21 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { p } // Absorbing elements. - (BinOp::Mul | BinOp::BitAnd, _, Left(0)) + ( + BinOp::Mul | BinOp::MulWithOverflow | BinOp::MulUnchecked | BinOp::BitAnd, + _, + Left(0), + ) | (BinOp::Rem, _, Left(1)) | ( - BinOp::Mul | BinOp::Div | BinOp::Rem | BinOp::BitAnd | BinOp::Shl | BinOp::Shr, + BinOp::Mul + | BinOp::MulWithOverflow + | BinOp::MulUnchecked + | BinOp::Div + | BinOp::Rem + | BinOp::BitAnd + | BinOp::Shl + | BinOp::Shr, Left(0), _, ) => self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty), @@ -1038,7 +1102,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { self.insert_scalar(Scalar::from_uint(ones, layout.size), lhs_ty) } // Sub/Xor with itself. - (BinOp::Sub | BinOp::BitXor, a, b) if a == b => { + (BinOp::Sub | BinOp::SubWithOverflow | BinOp::SubUnchecked | BinOp::BitXor, a, b) + if a == b => + { self.insert_scalar(Scalar::from_uint(0u128, layout.size), lhs_ty) } // Comparison: @@ -1052,7 +1118,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { _ => return None, }; - if checked { + if op.is_overflowing() { let false_val = self.insert_bool(false); Some(self.insert_tuple(vec![result, false_val])) } else { @@ -1082,6 +1148,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { return self.new_opaque(); } + let mut was_updated = false; + + // If that cast just casts away the metadata again, + if let PtrToPtr = kind + && let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) = + self.get(value) + && let ty::RawPtr(to_pointee, _) = to.kind() + && to_pointee.is_sized(self.tcx, self.param_env) + { + from = *data_pointer_ty; + value = fields[0]; + was_updated = true; + if *data_pointer_ty == to { + return Some(fields[0]); + } + } + if let PtrToPtr | PointerCoercion(MutToConstPointer) = kind && let Value::Cast { kind: inner_kind, value: inner_value, from: inner_from, to: _ } = *self.get(value) @@ -1090,9 +1173,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { from = inner_from; value = inner_value; *kind = PtrToPtr; + was_updated = true; if inner_from == to { return Some(inner_value); } + } + + if was_updated { if let Some(const_) = self.try_as_constant(value) { *operand = Operand::Constant(Box::new(const_)); } else if let Some(local) = self.try_as_local(value, location) { @@ -1108,7 +1195,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // Trivial case: we are fetching a statically known length. let place_ty = place.ty(self.local_decls, self.tcx).ty; if let ty::Array(_, len) = place_ty.kind() { - return self.insert_constant(Const::from_ty_const(*len, self.tcx)); + return self.insert_constant(Const::from_ty_const( + *len, + self.tcx.types.usize, + self.tcx, + )); } let mut inner = self.simplify_place_value(place, location)?; @@ -1130,7 +1221,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { && let Some(to) = to.builtin_deref(true) && let ty::Slice(..) = to.kind() { - return self.insert_constant(Const::from_ty_const(*len, self.tcx)); + return self.insert_constant(Const::from_ty_const( + *len, + self.tcx.types.usize, + self.tcx, + )); } // Fallback: a symbolic `Len`. @@ -1160,7 +1255,7 @@ fn op_to_prop_const<'tcx>( // If this constant has scalar ABI, return it as a `ConstValue::Scalar`. if let Abi::Scalar(abi::Scalar::Initialized { .. }) = op.layout.abi && let Ok(scalar) = ecx.read_scalar(op) - && scalar.try_to_int().is_ok() + && scalar.try_to_scalar_int().is_ok() { return Some(ConstValue::Scalar(scalar)); } diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 40db3e38fd3..6806c517c17 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -150,7 +150,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { return; } - let const_ = Const::from_ty_const(len, self.tcx); + let const_ = Const::from_ty_const(len, self.tcx.types.usize, self.tcx); let constant = ConstOperand { span: source_info.span, const_, user_ty: None }; *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant))); } diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 8b46658b322..6a20b46e7f9 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -356,15 +356,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { debug!("check_binary_op: reporting assert for {:?}", location); let panic = AssertKind::Overflow( op, - match l { - Some(l) => l.to_const_int(), - // Invent a dummy value, the diagnostic ignores it anyway - None => ConstInt::new( - ScalarInt::try_from_uint(1_u8, left_size).unwrap(), - left_ty.is_signed(), - left_ty.is_ptr_sized_integral(), - ), - }, + // Invent a dummy value, the diagnostic ignores it anyway + ConstInt::new( + ScalarInt::try_from_uint(1_u8, left_size).unwrap(), + left_ty.is_signed(), + left_ty.is_ptr_sized_integral(), + ), r.to_const_int(), ); self.report_assert_as_lint(location, AssertLintKind::ArithmeticOverflow, panic); @@ -625,9 +622,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let val = match null_op { NullOp::SizeOf => op_layout.size.bytes(), NullOp::AlignOf => op_layout.align.abi.bytes(), - NullOp::OffsetOf(fields) => { - op_layout.offset_of_subfield(self, fields.iter()).bytes() - } + NullOp::OffsetOf(fields) => self + .tcx + .offset_of_subfield(self.param_env, op_layout, fields.iter()) + .bytes(), NullOp::UbChecks => return None, }; ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into() @@ -786,8 +784,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { TerminatorKind::SwitchInt { ref discr, ref targets } => { if let Some(ref value) = self.eval_operand(discr) && let Some(value_const) = self.use_ecx(|this| this.ecx.read_scalar(value)) - && let Ok(constant) = value_const.try_to_int() - && let Ok(constant) = constant.try_to_bits(constant.size()) + && let Ok(constant) = value_const.to_bits(value_const.size()) { // We managed to evaluate the discriminant, so we know we only need to visit // one target. diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index a8741254ffb..551760f4703 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -55,7 +55,6 @@ mod remove_place_mention; // This pass is public to allow external drivers to perform MIR cleanup mod add_subtyping_projections; pub mod cleanup_post_borrowck; -mod const_debuginfo; mod copy_prop; mod coroutine; mod cost_checker; @@ -106,6 +105,7 @@ mod check_alignment; pub mod simplify; mod simplify_branches; mod simplify_comparison_integral; +mod single_use_consts; mod sroa; mod unreachable_enum_branching; mod unreachable_prop; @@ -211,7 +211,7 @@ fn remap_mir_for_const_eval_select<'tcx>( } fn is_mir_available(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - tcx.hir().maybe_body_owned_by(def_id).is_some() + tcx.mir_keys(()).contains(&def_id) } /// Finds the full set of `DefId`s within the current crate that have @@ -222,16 +222,6 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> { // All body-owners have MIR associated with them. set.extend(tcx.hir().body_owners()); - // Inline consts' bodies are created in - // typeck instead of during ast lowering, like all other bodies so far. - for def_id in tcx.hir().body_owners() { - // Incremental performance optimization: only load typeck results for things that actually have inline consts - if tcx.hir_owner_nodes(tcx.hir().body_owned_by(def_id).id().hir_id.owner).has_inline_consts - { - set.extend(tcx.typeck(def_id).inline_consts.values()) - } - } - // Additionally, tuple struct/variant constructors have MIR, but // they don't have a BodyId, so we need to build them separately. struct GatherCtors<'a> { @@ -603,7 +593,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &gvn::GVN, &simplify::SimplifyLocals::AfterGVN, &dataflow_const_prop::DataflowConstProp, - &const_debuginfo::ConstDebugInfo, + &single_use_consts::SingleUseConsts, &o1(simplify_branches::SimplifyConstCondition::AfterConstProp), &jump_threading::JumpThreading, &early_otherwise_branch::EarlyOtherwiseBranch, diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 1411d9be223..6ab4ec6fe7e 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -372,7 +372,7 @@ impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { } fn int_equal(l: ScalarInt, r: impl Into<u128>, size: Size) -> bool { - l.assert_int(l.size()) == ScalarInt::try_from_uint(r, size).unwrap().assert_int(size) + l.to_bits_unchecked() == ScalarInt::try_from_uint(r, size).unwrap().to_bits_unchecked() } // We first compare the two branches, and then the other branches need to fulfill the same conditions. diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs index 2070895c900..d5e72706661 100644 --- a/compiler/rustc_mir_transform/src/normalize_array_len.rs +++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs @@ -95,7 +95,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { *rvalue = Rvalue::Use(Operand::Constant(Box::new(ConstOperand { span: rustc_span::DUMMY_SP, user_ty: None, - const_: Const::from_ty_const(len, self.tcx), + const_: Const::from_ty_const(len, self.tcx.types.usize, self.tcx), }))); } self.super_rvalue(rvalue, loc); diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 7ec59cc983f..ecd1179ca99 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -500,14 +500,14 @@ impl<'tcx> Validator<'_, 'tcx> { } _ => None, }; - match rhs_val.map(|x| x.assert_uint(sz)) { + match rhs_val.map(|x| x.to_uint(sz)) { // for the zero test, int vs uint does not matter Some(x) if x != 0 => {} // okay _ => return Err(Unpromotable), // value not known or 0 -- not okay } // Furthermore, for signed divison, we also have to exclude `int::MIN / -1`. if lhs_ty.is_signed() { - match rhs_val.map(|x| x.assert_int(sz)) { + match rhs_val.map(|x| x.to_int(sz)) { Some(-1) | None => { // The RHS is -1 or unknown, so we have to be careful. // But is the LHS int::MIN? @@ -518,7 +518,7 @@ impl<'tcx> Validator<'_, 'tcx> { _ => None, }; let lhs_min = sz.signed_int_min(); - match lhs_val.map(|x| x.assert_int(sz)) { + match lhs_val.map(|x| x.to_int(sz)) { Some(x) if x != lhs_min => {} // okay _ => return Err(Unpromotable), // value not known or int::MIN -- not okay } diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs index 03907babf2b..e174cccdad6 100644 --- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs +++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs @@ -49,7 +49,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { let layout = tcx .layout_of(param_env.and(opt.branch_value_ty)) .expect("if we have an evaluated constant we must know the layout"); - int.assert_bits(layout.size) + int.to_bits(layout.size) } Scalar::Ptr(..) => continue, }; diff --git a/compiler/rustc_mir_transform/src/single_use_consts.rs b/compiler/rustc_mir_transform/src/single_use_consts.rs new file mode 100644 index 00000000000..93736e55996 --- /dev/null +++ b/compiler/rustc_mir_transform/src/single_use_consts.rs @@ -0,0 +1,199 @@ +use rustc_index::{bit_set::BitSet, IndexVec}; +use rustc_middle::bug; +use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; + +/// Various parts of MIR building introduce temporaries that are commonly not needed. +/// +/// Notably, `if CONST` and `match CONST` end up being used-once temporaries, which +/// obfuscates the structure for other passes and codegen, which would like to always +/// be able to just see the constant directly. +/// +/// At higher optimization levels fancier passes like GVN will take care of this +/// in a more general fashion, but this handles the easy cases so can run in debug. +/// +/// This only removes constants with a single-use because re-evaluating constants +/// isn't always an improvement, especially for large ones. +/// +/// It also removes *never*-used constants, since it had all the information +/// needed to do that too, including updating the debug info. +pub struct SingleUseConsts; + +impl<'tcx> MirPass<'tcx> for SingleUseConsts { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() > 0 + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let mut finder = SingleUseConstsFinder { + ineligible_locals: BitSet::new_empty(body.local_decls.len()), + locations: IndexVec::from_elem(LocationPair::new(), &body.local_decls), + locals_in_debug_info: BitSet::new_empty(body.local_decls.len()), + }; + + finder.ineligible_locals.insert_range(..=Local::from_usize(body.arg_count)); + + finder.visit_body(body); + + for (local, locations) in finder.locations.iter_enumerated() { + if finder.ineligible_locals.contains(local) { + continue; + } + + let Some(init_loc) = locations.init_loc else { + continue; + }; + + // We're only changing an operand, not the terminator kinds or successors + let basic_blocks = body.basic_blocks.as_mut_preserves_cfg(); + let init_statement = + basic_blocks[init_loc.block].statements[init_loc.statement_index].replace_nop(); + let StatementKind::Assign(place_and_rvalue) = init_statement.kind else { + bug!("No longer an assign?"); + }; + let (place, rvalue) = *place_and_rvalue; + assert_eq!(place.as_local(), Some(local)); + let Rvalue::Use(operand) = rvalue else { bug!("No longer a use?") }; + + let mut replacer = LocalReplacer { tcx, local, operand: Some(operand) }; + + if finder.locals_in_debug_info.contains(local) { + for var_debug_info in &mut body.var_debug_info { + replacer.visit_var_debug_info(var_debug_info); + } + } + + let Some(use_loc) = locations.use_loc else { continue }; + + let use_block = &mut basic_blocks[use_loc.block]; + if let Some(use_statement) = use_block.statements.get_mut(use_loc.statement_index) { + replacer.visit_statement(use_statement, use_loc); + } else { + replacer.visit_terminator(use_block.terminator_mut(), use_loc); + } + + if replacer.operand.is_some() { + bug!( + "operand wasn't used replacing local {local:?} with locations {locations:?} in body {body:#?}" + ); + } + } + } +} + +#[derive(Copy, Clone, Debug)] +struct LocationPair { + init_loc: Option<Location>, + use_loc: Option<Location>, +} + +impl LocationPair { + fn new() -> Self { + Self { init_loc: None, use_loc: None } + } +} + +struct SingleUseConstsFinder { + ineligible_locals: BitSet<Local>, + locations: IndexVec<Local, LocationPair>, + locals_in_debug_info: BitSet<Local>, +} + +impl<'tcx> Visitor<'tcx> for SingleUseConstsFinder { + fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { + if let Some(local) = place.as_local() + && let Rvalue::Use(operand) = rvalue + && let Operand::Constant(_) = operand + { + let locations = &mut self.locations[local]; + if locations.init_loc.is_some() { + self.ineligible_locals.insert(local); + } else { + locations.init_loc = Some(location); + } + } else { + self.super_assign(place, rvalue, location); + } + } + + fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { + if let Some(place) = operand.place() + && let Some(local) = place.as_local() + { + let locations = &mut self.locations[local]; + if locations.use_loc.is_some() { + self.ineligible_locals.insert(local); + } else { + locations.use_loc = Some(location); + } + } else { + self.super_operand(operand, location); + } + } + + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + match &statement.kind { + // Storage markers are irrelevant to this. + StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => {} + _ => self.super_statement(statement, location), + } + } + + fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo<'tcx>) { + if let VarDebugInfoContents::Place(place) = &var_debug_info.value + && let Some(local) = place.as_local() + { + self.locals_in_debug_info.insert(local); + } else { + self.super_var_debug_info(var_debug_info); + } + } + + fn visit_local(&mut self, local: Local, _context: PlaceContext, _location: Location) { + // If there's any path that gets here, rather than being understood elsewhere, + // then we'd better not do anything with this local. + self.ineligible_locals.insert(local); + } +} + +struct LocalReplacer<'tcx> { + tcx: TyCtxt<'tcx>, + local: Local, + operand: Option<Operand<'tcx>>, +} + +impl<'tcx> MutVisitor<'tcx> for LocalReplacer<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_operand(&mut self, operand: &mut Operand<'tcx>, _location: Location) { + if let Operand::Copy(place) | Operand::Move(place) = operand + && let Some(local) = place.as_local() + && local == self.local + { + *operand = self.operand.take().unwrap_or_else(|| { + bug!("there was a second use of the operand"); + }); + } + } + + fn visit_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo<'tcx>) { + if let VarDebugInfoContents::Place(place) = &var_debug_info.value + && let Some(local) = place.as_local() + && local == self.local + { + let const_op = self + .operand + .as_ref() + .unwrap_or_else(|| { + bug!("the operand was already stolen"); + }) + .constant() + .unwrap() + .clone(); + var_debug_info.value = VarDebugInfoContents::Const(const_op); + } + } +} diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 3b4d4c93877..586c1254995 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -5,12 +5,12 @@ use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; use rustc_infer::traits::Reveal; use rustc_middle::mir::coverage::CoverageKind; -use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{ - self, CoroutineArgsExt, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt, Variance, + self, CoroutineArgsExt, InstanceDef, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt, + Variance, }; use rustc_middle::{bug, span_bug}; use rustc_target::abi::{Size, FIRST_VARIANT}; @@ -1478,7 +1478,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { }); for (value, _) in targets.iter() { - if Scalar::<()>::try_from_uint(value, size).is_none() { + if ScalarInt::try_from_uint(value, size).is_none() { self.fail( location, format!("the value {value:#x} is not a proper {switch_ty:?}"), diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 9487692662b..61680dbfaf5 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -207,8 +207,8 @@ mod move_check; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{par_for_each_in, LRef, MTLock}; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; @@ -251,10 +251,10 @@ pub enum MonoItemCollectionStrategy { pub struct UsageMap<'tcx> { // Maps every mono item to the mono items used by it. - used_map: FxHashMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>, + used_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>, // Maps every mono item to the mono items that use it. - user_map: FxHashMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>, + user_map: UnordMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>>, } type MonoItems<'tcx> = Vec<Spanned<MonoItem<'tcx>>>; @@ -262,10 +262,10 @@ type MonoItems<'tcx> = Vec<Spanned<MonoItem<'tcx>>>; /// The state that is shared across the concurrent threads that are doing collection. struct SharedState<'tcx> { /// Items that have been or are currently being recursively collected. - visited: MTLock<FxHashSet<MonoItem<'tcx>>>, + visited: MTLock<UnordSet<MonoItem<'tcx>>>, /// Items that have been or are currently being recursively treated as "mentioned", i.e., their /// consts are evaluated but nothing is added to the collection. - mentioned: MTLock<FxHashSet<MonoItem<'tcx>>>, + mentioned: MTLock<UnordSet<MonoItem<'tcx>>>, /// Which items are being used where, for better errors. usage_map: MTLock<UsageMap<'tcx>>, } @@ -290,7 +290,7 @@ enum CollectionMode { impl<'tcx> UsageMap<'tcx> { fn new() -> UsageMap<'tcx> { - UsageMap { used_map: FxHashMap::default(), user_map: FxHashMap::default() } + UsageMap { used_map: Default::default(), user_map: Default::default() } } fn record_used<'a>( @@ -668,7 +668,7 @@ struct MirUsedCollector<'a, 'tcx> { used_items: &'a mut MonoItems<'tcx>, /// See the comment in `collect_items_of_instance` for the purpose of this set. /// Note that this contains *not-monomorphized* items! - used_mentioned_items: &'a mut FxHashSet<MentionedItem<'tcx>>, + used_mentioned_items: &'a mut UnordSet<MentionedItem<'tcx>>, instance: Instance<'tcx>, visiting_call_terminator: bool, move_check: move_check::MoveCheckState, @@ -1272,7 +1272,7 @@ fn collect_items_of_instance<'tcx>( // mentioned item. So instead we collect all pre-monomorphized `MentionedItem` that were already // added to `used_items` in a hash set, which can efficiently query in the // `body.mentioned_items` loop below without even having to monomorphize the item. - let mut used_mentioned_items = FxHashSet::<MentionedItem<'tcx>>::default(); + let mut used_mentioned_items = Default::default(); let mut collector = MirUsedCollector { tcx, body, @@ -1628,10 +1628,10 @@ fn create_mono_items_for_default_impls<'tcx>( //=----------------------------------------------------------------------------- #[instrument(skip(tcx, strategy), level = "debug")] -pub fn collect_crate_mono_items( - tcx: TyCtxt<'_>, +pub(crate) fn collect_crate_mono_items<'tcx>( + tcx: TyCtxt<'tcx>, strategy: MonoItemCollectionStrategy, -) -> (FxHashSet<MonoItem<'_>>, UsageMap<'_>) { +) -> (Vec<MonoItem<'tcx>>, UsageMap<'tcx>) { let _prof_timer = tcx.prof.generic_activity("monomorphization_collector"); let roots = tcx @@ -1641,8 +1641,8 @@ pub fn collect_crate_mono_items( debug!("building mono item graph, beginning at roots"); let mut state = SharedState { - visited: MTLock::new(FxHashSet::default()), - mentioned: MTLock::new(FxHashSet::default()), + visited: MTLock::new(UnordSet::default()), + mentioned: MTLock::new(UnordSet::default()), usage_map: MTLock::new(UsageMap::new()), }; let recursion_limit = tcx.recursion_limit(); @@ -1665,5 +1665,11 @@ pub fn collect_crate_mono_items( }); } - (state.visited.into_inner(), state.usage_map.into_inner()) + // The set of MonoItems was created in an inherently indeterministic order because + // of parallelism. We sort it here to ensure that the output is deterministic. + let mono_items = tcx.with_stable_hashing_context(move |ref hcx| { + state.visited.into_inner().into_sorted(hcx, true) + }); + + (mono_items, state.usage_map.into_inner()) } diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index b298fe5813f..eb5f8d92603 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,6 +1,5 @@ #![feature(array_windows)] #![feature(is_sorted)] -#![allow(rustc::potential_query_instability)] use rustc_hir::lang_items::LangItem; use rustc_middle::bug; diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 21d52004728..336341f4e74 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -98,8 +98,9 @@ use std::fs::{self, File}; use std::io::{BufWriter, Write}; use std::path::{Path, PathBuf}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sync; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdSet, LOCAL_CRATE}; use rustc_hir::definitions::DefPathDataName; @@ -131,7 +132,7 @@ struct PlacedMonoItems<'tcx> { /// The codegen units, sorted by name to make things deterministic. codegen_units: Vec<CodegenUnit<'tcx>>, - internalization_candidates: FxHashSet<MonoItem<'tcx>>, + internalization_candidates: UnordSet<MonoItem<'tcx>>, } // The output CGUs are sorted by name. @@ -197,9 +198,9 @@ fn place_mono_items<'tcx, I>(cx: &PartitioningCx<'_, 'tcx>, mono_items: I) -> Pl where I: Iterator<Item = MonoItem<'tcx>>, { - let mut codegen_units = FxHashMap::default(); + let mut codegen_units = UnordMap::default(); let is_incremental_build = cx.tcx.sess.opts.incremental.is_some(); - let mut internalization_candidates = FxHashSet::default(); + let mut internalization_candidates = UnordSet::default(); // Determine if monomorphizations instantiated in this crate will be made // available to downstream crates. This depends on whether we are in @@ -209,7 +210,7 @@ where cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics(); let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); - let cgu_name_cache = &mut FxHashMap::default(); + let cgu_name_cache = &mut UnordMap::default(); for mono_item in mono_items { // Handle only root (GloballyShared) items directly here. Inlined (LocalCopy) items @@ -260,7 +261,7 @@ where // going via another root item. This includes drop-glue, functions from // external crates, and local functions the definition of which is // marked with `#[inline]`. - let mut reachable_inlined_items = FxHashSet::default(); + let mut reachable_inlined_items = FxIndexSet::default(); get_reachable_inlined_items(cx.tcx, mono_item, cx.usage_map, &mut reachable_inlined_items); // Add those inlined items. It's possible an inlined item is reachable @@ -284,8 +285,9 @@ where codegen_units.insert(cgu_name, CodegenUnit::new(cgu_name)); } - let mut codegen_units: Vec<_> = codegen_units.into_values().collect(); - codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); + let mut codegen_units: Vec<_> = cx.tcx.with_stable_hashing_context(|ref hcx| { + codegen_units.into_items().map(|(_, cgu)| cgu).collect_sorted(hcx, true) + }); for cgu in codegen_units.iter_mut() { cgu.compute_size_estimate(); @@ -297,7 +299,7 @@ where tcx: TyCtxt<'tcx>, item: MonoItem<'tcx>, usage_map: &UsageMap<'tcx>, - visited: &mut FxHashSet<MonoItem<'tcx>>, + visited: &mut FxIndexSet<MonoItem<'tcx>>, ) { usage_map.for_each_inlined_used_item(tcx, item, |inlined_item| { let is_new = visited.insert(inlined_item); @@ -320,7 +322,7 @@ fn merge_codegen_units<'tcx>( assert!(codegen_units.is_sorted_by(|a, b| a.name().as_str() <= b.name().as_str())); // This map keeps track of what got merged into what. - let mut cgu_contents: FxHashMap<Symbol, Vec<Symbol>> = + let mut cgu_contents: UnordMap<Symbol, Vec<Symbol>> = codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name()])).collect(); // If N is the maximum number of CGUs, and the CGUs are sorted from largest @@ -422,22 +424,24 @@ fn merge_codegen_units<'tcx>( // For CGUs that contain the code of multiple modules because of the // merging done above, we use a concatenation of the names of all // contained CGUs. - let new_cgu_names: FxHashMap<Symbol, String> = cgu_contents - .into_iter() - // This `filter` makes sure we only update the name of CGUs that - // were actually modified by merging. - .filter(|(_, cgu_contents)| cgu_contents.len() > 1) - .map(|(current_cgu_name, cgu_contents)| { - let mut cgu_contents: Vec<&str> = cgu_contents.iter().map(|s| s.as_str()).collect(); - - // Sort the names, so things are deterministic and easy to - // predict. We are sorting primitive `&str`s here so we can - // use unstable sort. - cgu_contents.sort_unstable(); - - (current_cgu_name, cgu_contents.join("--")) - }) - .collect(); + let new_cgu_names = UnordMap::from( + cgu_contents + .items() + // This `filter` makes sure we only update the name of CGUs that + // were actually modified by merging. + .filter(|(_, cgu_contents)| cgu_contents.len() > 1) + .map(|(current_cgu_name, cgu_contents)| { + let mut cgu_contents: Vec<&str> = + cgu_contents.iter().map(|s| s.as_str()).collect(); + + // Sort the names, so things are deterministic and easy to + // predict. We are sorting primitive `&str`s here so we can + // use unstable sort. + cgu_contents.sort_unstable(); + + (*current_cgu_name, cgu_contents.join("--")) + }), + ); for cgu in codegen_units.iter_mut() { if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { @@ -511,7 +515,7 @@ fn compute_inlined_overlap<'tcx>(cgu1: &CodegenUnit<'tcx>, cgu2: &CodegenUnit<'t fn internalize_symbols<'tcx>( cx: &PartitioningCx<'_, 'tcx>, codegen_units: &mut [CodegenUnit<'tcx>], - internalization_candidates: FxHashSet<MonoItem<'tcx>>, + internalization_candidates: UnordSet<MonoItem<'tcx>>, ) { /// For symbol internalization, we need to know whether a symbol/mono-item /// is used from outside the codegen unit it is defined in. This type is @@ -522,7 +526,7 @@ fn internalize_symbols<'tcx>( MultipleCgus, } - let mut mono_item_placements = FxHashMap::default(); + let mut mono_item_placements = UnordMap::default(); let single_codegen_unit = codegen_units.len() == 1; if !single_codegen_unit { @@ -739,7 +743,7 @@ fn mono_item_linkage_and_visibility<'tcx>( (Linkage::External, vis) } -type CguNameCache = FxHashMap<(DefId, bool), Symbol>; +type CguNameCache = UnordMap<(DefId, bool), Symbol>; fn static_visibility<'tcx>( tcx: TyCtxt<'tcx>, @@ -932,7 +936,7 @@ fn debug_dump<'a, 'tcx: 'a>(tcx: TyCtxt<'tcx>, label: &str, cgus: &[CodegenUnit< // // Also, unreached inlined items won't be counted here. This is fine. - let mut inlined_items = FxHashSet::default(); + let mut inlined_items = UnordSet::default(); let mut root_items = 0; let mut unique_inlined_items = 0; @@ -1164,7 +1168,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co } if tcx.sess.opts.unstable_opts.print_mono_items.is_some() { - let mut item_to_cgus: FxHashMap<_, Vec<_>> = Default::default(); + let mut item_to_cgus: UnordMap<_, Vec<_>> = Default::default(); for cgu in codegen_units { for (&mono_item, &data) in cgu.items() { @@ -1240,7 +1244,7 @@ fn dump_mono_items_stats<'tcx>( let mut file = BufWriter::new(file); // Gather instantiated mono items grouped by def_id - let mut items_per_def_id: FxHashMap<_, Vec<_>> = Default::default(); + let mut items_per_def_id: FxIndexMap<_, Vec<_>> = Default::default(); for cgu in codegen_units { cgu.items() .keys() diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index dc13766d145..a3ca9e9f9cf 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -263,7 +263,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { fn visit_constant(&mut self, ct: &mir::ConstOperand<'tcx>, location: Location) { match ct.const_ { - mir::Const::Ty(c) => { + mir::Const::Ty(_, c) => { c.visit_with(self); } mir::Const::Unevaluated(mir::UnevaluatedConst { def, args: _, promoted }, ty) => { diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index 8bcc21d82f8..50dbc991f8f 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -4,20 +4,10 @@ version = "0.0.0" edition = "2021" [dependencies] +# tidy-alphabetical-start rustc_type_ir = { path = "../rustc_type_ir", default-features = false } -derivative = "2.2.0" -rustc_macros = { path = "../rustc_macros", optional = true } -rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } -rustc_serialize = { path = "../rustc_serialize", optional = true } -rustc_data_structures = { path = "../rustc_data_structures", optional = true } -rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false } +# tidy-alphabetical-end [features] default = ["nightly"] -nightly = [ - "rustc_type_ir/nightly", - "rustc_macros", - "rustc_serialize", - "rustc_data_structures", - "rustc_ast_ir/nightly", -] +nightly = ["rustc_type_ir/nightly"] diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 127ebde5fec..f22e24ef654 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -386,23 +386,15 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> } fn fold_const(&mut self, c: I::Const) -> I::Const { - // We could canonicalize all consts with static types, but the only ones we - // *really* need to worry about are the ones that we end up putting into `CanonicalVarKind` - // since canonical vars can't reference other canonical vars. - let ty = c - .ty() - .fold_with(&mut RegionsToStatic { interner: self.interner(), binder: ty::INNERMOST }); let kind = match c.kind() { ty::ConstKind::Infer(i) => match i { ty::InferConst::Var(vid) => { - // We compare `kind`s here because we've folded the `ty` with `RegionsToStatic` - // so we'll get a mismatch in types if it actually changed any regions. assert_eq!( - self.infcx.opportunistic_resolve_ct_var(vid, ty).kind(), - c.kind(), - "region vid should have been resolved fully before canonicalization" + self.infcx.opportunistic_resolve_ct_var(vid), + c, + "const vid should have been resolved fully before canonicalization" ); - CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), ty) + CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap()) } ty::InferConst::EffectVar(_) => CanonicalVarKind::Effect, ty::InferConst::Fresh(_) => todo!(), @@ -410,23 +402,21 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> ty::ConstKind::Placeholder(placeholder) => match self.canonicalize_mode { CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst( PlaceholderLike::new(placeholder.universe(), self.variables.len().into()), - ty, ), CanonicalizeMode::Response { .. } => { - CanonicalVarKind::PlaceholderConst(placeholder, ty) + CanonicalVarKind::PlaceholderConst(placeholder) } }, ty::ConstKind::Param(_) => match self.canonicalize_mode { CanonicalizeMode::Input => CanonicalVarKind::PlaceholderConst( PlaceholderLike::new(ty::UniverseIndex::ROOT, self.variables.len().into()), - ty, ), CanonicalizeMode::Response { .. } => panic!("param ty in response: {c:?}"), }, // FIXME: See comment above -- we could fold the region separately or something. ty::ConstKind::Bound(_, _) | ty::ConstKind::Unevaluated(_) - | ty::ConstKind::Value(_) + | ty::ConstKind::Value(_, _) | ty::ConstKind::Error(_) | ty::ConstKind::Expr(_) => return c.super_fold_with(self), }; @@ -440,34 +430,6 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> }), ); - Const::new_anon_bound(self.interner(), self.binder_index, var, ty) - } -} - -struct RegionsToStatic<I> { - interner: I, - binder: ty::DebruijnIndex, -} - -impl<I: Interner> TypeFolder<I> for RegionsToStatic<I> { - fn interner(&self) -> I { - self.interner - } - - fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T> - where - T: TypeFoldable<I>, - { - self.binder.shift_in(1); - let t = t.super_fold_with(self); - self.binder.shift_out(1); - t - } - - fn fold_region(&mut self, r: I::Region) -> I::Region { - match r.kind() { - ty::ReBound(db, _) if self.binder > db => r, - _ => Region::new_static(self.interner()), - } + Const::new_anon_bound(self.interner(), self.binder_index, var) } } diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index 1333b4aa7d8..5c00b6978d6 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -7,11 +7,11 @@ use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; // EAGER RESOLUTION /// Resolves ty, region, and const vars to their inferred values or their root vars. -pub struct EagerResolver< - 'a, +pub struct EagerResolver<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner> +where Infcx: InferCtxtLike<Interner = I>, - I: Interner = <Infcx as InferCtxtLike>::Interner, -> { + I: Interner, +{ infcx: &'a Infcx, } @@ -58,8 +58,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> for EagerRes fn fold_const(&mut self, c: I::Const) -> I::Const { match c.kind() { ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { - let ty = c.ty().fold_with(self); - let resolved = self.infcx.opportunistic_resolve_ct_var(vid, ty); + let resolved = self.infcx.opportunistic_resolve_ct_var(vid); if c != resolved && resolved.has_infer() { resolved.fold_with(self) } else { @@ -67,9 +66,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> for EagerRes } } ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => { - let bool = Ty::new_bool(self.infcx.interner()); - debug_assert_eq!(c.ty(), bool); - self.infcx.opportunistic_resolve_effect_var(vid, bool) + self.infcx.opportunistic_resolve_effect_var(vid) } _ => { if c.has_infer() { diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 04f855e4f55..f678d11213c 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -622,8 +622,6 @@ parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allo parse_out_of_range_hex_escape = out of range hex escape .label = must be a character in the range [\x00-\x7f] -parse_outer_attr_ambiguous = ambiguous outer attributes - parse_outer_attr_explanation = outer attributes, like `#[test]`, annotate the item following them parse_outer_attribute_not_allowed_on_if_else = outer attributes are not allowed on `if` and `else` branches diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 3f08a830b0c..6c1fcbe06fc 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -496,15 +496,6 @@ pub(crate) struct OuterAttributeNotAllowedOnIfElse { } #[derive(Diagnostic)] -#[diag(parse_outer_attr_ambiguous)] -pub(crate) struct AmbiguousOuterAttributes { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub sugg: WrapInParentheses, -} - -#[derive(Diagnostic)] #[diag(parse_missing_in_in_for_loop)] pub(crate) struct MissingInInForLoop { #[primary_span] diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index d3a6a033978..43f4963b27a 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -42,7 +42,7 @@ pub(crate) struct UnmatchedDelim { pub candidate_span: Option<Span>, } -pub(crate) fn parse_token_trees<'psess, 'src>( +pub(crate) fn lex_token_trees<'psess, 'src>( psess: &'psess ParseSess, mut src: &'src str, mut start_pos: BytePos, @@ -66,7 +66,7 @@ pub(crate) fn parse_token_trees<'psess, 'src>( last_lifetime: None, }; let (stream, res, unmatched_delims) = - tokentrees::TokenTreesReader::parse_all_token_trees(string_reader); + tokentrees::TokenTreesReader::lex_all_token_trees(string_reader); match res { Ok(()) if unmatched_delims.is_empty() => Ok(stream), _ => { diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index eabe0226b2f..f7645446081 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -2,6 +2,7 @@ use super::diagnostics::report_suspicious_mismatch_block; use super::diagnostics::same_indentation_level; use super::diagnostics::TokenTreeDiagInfo; use super::{StringReader, UnmatchedDelim}; +use crate::Parser; use rustc_ast::token::{self, Delimiter, Token}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast_pretty::pprust::token_to_string; @@ -17,7 +18,7 @@ pub(super) struct TokenTreesReader<'psess, 'src> { } impl<'psess, 'src> TokenTreesReader<'psess, 'src> { - pub(super) fn parse_all_token_trees( + pub(super) fn lex_all_token_trees( string_reader: StringReader<'psess, 'src>, ) -> (TokenStream, Result<(), Vec<PErr<'psess>>>, Vec<UnmatchedDelim>) { let mut tt_reader = TokenTreesReader { @@ -25,14 +26,13 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { token: Token::dummy(), diag_info: TokenTreeDiagInfo::default(), }; - let (_open_spacing, stream, res) = - tt_reader.parse_token_trees(/* is_delimited */ false); + let (_open_spacing, stream, res) = tt_reader.lex_token_trees(/* is_delimited */ false); (stream, res, tt_reader.diag_info.unmatched_delims) } - // Parse a stream of tokens into a list of `TokenTree`s. The `Spacing` in - // the result is that of the opening delimiter. - fn parse_token_trees( + // Lex into a token stream. The `Spacing` in the result is that of the + // opening delimiter. + fn lex_token_trees( &mut self, is_delimited: bool, ) -> (Spacing, TokenStream, Result<(), Vec<PErr<'psess>>>) { @@ -42,12 +42,10 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { let mut buf = Vec::new(); loop { match self.token.kind { - token::OpenDelim(delim) => { - buf.push(match self.parse_token_tree_open_delim(delim) { - Ok(val) => val, - Err(errs) => return (open_spacing, TokenStream::new(buf), Err(errs)), - }) - } + token::OpenDelim(delim) => buf.push(match self.lex_token_tree_open_delim(delim) { + Ok(val) => val, + Err(errs) => return (open_spacing, TokenStream::new(buf), Err(errs)), + }), token::CloseDelim(delim) => { return ( open_spacing, @@ -95,24 +93,24 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { err } - fn parse_token_tree_open_delim( + fn lex_token_tree_open_delim( &mut self, open_delim: Delimiter, ) -> Result<TokenTree, Vec<PErr<'psess>>> { - // The span for beginning of the delimited section + // The span for beginning of the delimited section. let pre_span = self.token.span; self.diag_info.open_braces.push((open_delim, self.token.span)); - // Parse the token trees within the delimiters. + // Lex the token trees within the delimiters. // We stop at any delimiter so we can try to recover if the user // uses an incorrect delimiter. - let (open_spacing, tts, res) = self.parse_token_trees(/* is_delimited */ true); + let (open_spacing, tts, res) = self.lex_token_trees(/* is_delimited */ true); if let Err(errs) = res { return Err(self.unclosed_delim_err(tts, errs)); } - // Expand to cover the entire delimited token tree + // Expand to cover the entire delimited token tree. let delim_span = DelimSpan::from_pair(pre_span, self.token.span); let sm = self.string_reader.psess.source_map(); @@ -150,7 +148,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { self.diag_info.last_unclosed_found_span = Some(self.token.span); // This is a conservative error: only report the last unclosed // delimiter. The previous unclosed delimiters could actually be - // closed! The parser just hasn't gotten to them yet. + // closed! The lexer just hasn't gotten to them yet. if let Some(&(_, sp)) = self.diag_info.open_braces.last() { unclosed_delimiter = Some(sp); }; @@ -234,11 +232,11 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { ) -> Vec<PErr<'psess>> { // If there are unclosed delims, see if there are diff markers and if so, point them // out instead of complaining about the unclosed delims. - let mut parser = crate::stream_to_parser(self.string_reader.psess, tts, None); + let mut parser = Parser::new(self.string_reader.psess, tts, None); let mut diff_errs = vec![]; - // Suggest removing a `{` we think appears in an `if`/`while` condition - // We want to suggest removing a `{` only if we think we're in an `if`/`while` condition, but - // we have no way of tracking this in the lexer itself, so we piggyback on the parser + // Suggest removing a `{` we think appears in an `if`/`while` condition. + // We want to suggest removing a `{` only if we think we're in an `if`/`while` condition, + // but we have no way of tracking this in the lexer itself, so we piggyback on the parser. let mut in_cond = false; while parser.token != token::Eof { if let Err(diff_err) = parser.err_vcs_conflict_marker() { @@ -249,14 +247,15 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { parser.token.kind, token::CloseDelim(Delimiter::Brace) | token::FatArrow ) { - // end of the `if`/`while` body, or the end of a `match` guard + // End of the `if`/`while` body, or the end of a `match` guard. in_cond = false; } else if in_cond && parser.token == token::OpenDelim(Delimiter::Brace) { // Store the `&&` and `let` to use their spans later when creating the diagnostic let maybe_andand = parser.look_ahead(1, |t| t.clone()); let maybe_let = parser.look_ahead(2, |t| t.clone()); if maybe_andand == token::OpenDelim(Delimiter::Brace) { - // This might be the beginning of the `if`/`while` body (i.e., the end of the condition) + // This might be the beginning of the `if`/`while` body (i.e., the end of the + // condition). in_cond = false; } else if maybe_andand == token::AndAnd && maybe_let.is_keyword(kw::Let) { let mut err = parser.dcx().struct_span_err( @@ -288,8 +287,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { } fn close_delim_err(&mut self, delim: Delimiter) -> PErr<'psess> { - // An unexpected closing delimiter (i.e., there is no - // matching opening delimiter). + // An unexpected closing delimiter (i.e., there is no matching opening delimiter). let token_str = token_to_string(&self.token); let msg = format!("unexpected closing delimiter: `{token_str}`"); let mut err = self.string_reader.psess.dcx.struct_span_err(self.token.span, msg); diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index c9470151a7b..8eb299108d1 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -129,42 +129,42 @@ pub(super) const UNICODE_ARRAY: &[(char, &str, &str)] = &[ ('。', "Ideographic Full Stop", "."), ('︒', "Presentation Form For Vertical Ideographic Full Stop", "."), - ('՝', "Armenian Comma", "\'"), - (''', "Fullwidth Apostrophe", "\'"), - ('‘', "Left Single Quotation Mark", "\'"), - ('’', "Right Single Quotation Mark", "\'"), - ('‛', "Single High-Reversed-9 Quotation Mark", "\'"), - ('′', "Prime", "\'"), - ('‵', "Reversed Prime", "\'"), - ('՚', "Armenian Apostrophe", "\'"), - ('׳', "Hebrew Punctuation Geresh", "\'"), - ('`', "Grave Accent", "\'"), - ('`', "Greek Varia", "\'"), - ('`', "Fullwidth Grave Accent", "\'"), - ('´', "Acute Accent", "\'"), - ('΄', "Greek Tonos", "\'"), - ('´', "Greek Oxia", "\'"), - ('᾽', "Greek Koronis", "\'"), - ('᾿', "Greek Psili", "\'"), - ('῾', "Greek Dasia", "\'"), - ('ʹ', "Modifier Letter Prime", "\'"), - ('ʹ', "Greek Numeral Sign", "\'"), - ('ˈ', "Modifier Letter Vertical Line", "\'"), - ('ˊ', "Modifier Letter Acute Accent", "\'"), - ('ˋ', "Modifier Letter Grave Accent", "\'"), - ('˴', "Modifier Letter Middle Grave Accent", "\'"), - ('ʻ', "Modifier Letter Turned Comma", "\'"), - ('ʽ', "Modifier Letter Reversed Comma", "\'"), - ('ʼ', "Modifier Letter Apostrophe", "\'"), - ('ʾ', "Modifier Letter Right Half Ring", "\'"), - ('ꞌ', "Latin Small Letter Saltillo", "\'"), - ('י', "Hebrew Letter Yod", "\'"), - ('ߴ', "Nko High Tone Apostrophe", "\'"), - ('ߵ', "Nko Low Tone Apostrophe", "\'"), - ('ᑊ', "Canadian Syllabics West-Cree P", "\'"), - ('ᛌ', "Runic Letter Short-Twig-Sol S", "\'"), - ('𖽑', "Miao Sign Aspiration", "\'"), - ('𖽒', "Miao Sign Reformed Voicing", "\'"), + ('՝', "Armenian Comma", "'"), + (''', "Fullwidth Apostrophe", "'"), + ('‘', "Left Single Quotation Mark", "'"), + ('’', "Right Single Quotation Mark", "'"), + ('‛', "Single High-Reversed-9 Quotation Mark", "'"), + ('′', "Prime", "'"), + ('‵', "Reversed Prime", "'"), + ('՚', "Armenian Apostrophe", "'"), + ('׳', "Hebrew Punctuation Geresh", "'"), + ('`', "Grave Accent", "'"), + ('`', "Greek Varia", "'"), + ('`', "Fullwidth Grave Accent", "'"), + ('´', "Acute Accent", "'"), + ('΄', "Greek Tonos", "'"), + ('´', "Greek Oxia", "'"), + ('᾽', "Greek Koronis", "'"), + ('᾿', "Greek Psili", "'"), + ('῾', "Greek Dasia", "'"), + ('ʹ', "Modifier Letter Prime", "'"), + ('ʹ', "Greek Numeral Sign", "'"), + ('ˈ', "Modifier Letter Vertical Line", "'"), + ('ˊ', "Modifier Letter Acute Accent", "'"), + ('ˋ', "Modifier Letter Grave Accent", "'"), + ('˴', "Modifier Letter Middle Grave Accent", "'"), + ('ʻ', "Modifier Letter Turned Comma", "'"), + ('ʽ', "Modifier Letter Reversed Comma", "'"), + ('ʼ', "Modifier Letter Apostrophe", "'"), + ('ʾ', "Modifier Letter Right Half Ring", "'"), + ('ꞌ', "Latin Small Letter Saltillo", "'"), + ('י', "Hebrew Letter Yod", "'"), + ('ߴ', "Nko High Tone Apostrophe", "'"), + ('ߵ', "Nko Low Tone Apostrophe", "'"), + ('ᑊ', "Canadian Syllabics West-Cree P", "'"), + ('ᛌ', "Runic Letter Short-Twig-Sol S", "'"), + ('𖽑', "Miao Sign Aspiration", "'"), + ('𖽒', "Miao Sign Reformed Voicing", "'"), ('᳓', "Vedic Sign Nihshvasa", "\""), ('"', "Fullwidth Quotation Mark", "\""), @@ -298,6 +298,7 @@ pub(super) const UNICODE_ARRAY: &[(char, &str, &str)] = &[ ('〉', "Right Angle Bracket", ">"), ('》', "Right Double Angle Bracket", ">"), ('>', "Fullwidth Greater-Than Sign", ">"), + ('⩵', "Two Consecutive Equals Signs", "==") ]; @@ -332,7 +333,7 @@ const ASCII_ARRAY: &[(&str, &str, Option<token::TokenKind>)] = &[ (">", "Greater-Than Sign", Some(token::Gt)), // FIXME: Literals are already lexed by this point, so we can't recover gracefully just by // spitting the correct token out. - ("\'", "Single Quote", None), + ("'", "Single Quote", None), ("\"", "Quotation Mark", None), ]; diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 322739be3fb..b316327a262 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -34,84 +34,41 @@ mod errors; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } -// A bunch of utility functions of the form `parse_<thing>_from_<source>` -// where <thing> includes crate, expr, item, stmt, tts, and one that -// uses a HOF to parse anything, and <source> includes file and -// `source_str`. - -/// A variant of 'panictry!' that works on a `Vec<Diag>` instead of a single `Diag`. -macro_rules! panictry_buffer { - ($e:expr) => {{ - use std::result::Result::{Err, Ok}; - match $e { - Ok(e) => e, - Err(errs) => { - for e in errs { - e.emit(); - } - FatalError.raise() +// Unwrap the result if `Ok`, otherwise emit the diagnostics and abort. +pub fn unwrap_or_emit_fatal<T>(expr: Result<T, Vec<Diag<'_>>>) -> T { + match expr { + Ok(expr) => expr, + Err(errs) => { + for err in errs { + err.emit(); } + FatalError.raise() } - }}; -} - -pub fn parse_crate_from_file<'a>(input: &Path, psess: &'a ParseSess) -> PResult<'a, ast::Crate> { - let mut parser = new_parser_from_file(psess, input, None); - parser.parse_crate_mod() -} - -pub fn parse_crate_attrs_from_file<'a>( - input: &Path, - psess: &'a ParseSess, -) -> PResult<'a, ast::AttrVec> { - let mut parser = new_parser_from_file(psess, input, None); - parser.parse_inner_attributes() -} - -pub fn parse_crate_from_source_str( - name: FileName, - source: String, - psess: &ParseSess, -) -> PResult<'_, ast::Crate> { - new_parser_from_source_str(psess, name, source).parse_crate_mod() -} - -pub fn parse_crate_attrs_from_source_str( - name: FileName, - source: String, - psess: &ParseSess, -) -> PResult<'_, ast::AttrVec> { - new_parser_from_source_str(psess, name, source).parse_inner_attributes() -} - -pub fn parse_stream_from_source_str( - name: FileName, - source: String, - psess: &ParseSess, - override_span: Option<Span>, -) -> TokenStream { - source_file_to_stream(psess, psess.source_map().new_source_file(name, source), override_span) -} - -/// Creates a new parser from a source string. -pub fn new_parser_from_source_str(psess: &ParseSess, name: FileName, source: String) -> Parser<'_> { - panictry_buffer!(maybe_new_parser_from_source_str(psess, name, source)) + } } -/// Creates a new parser from a source string. Returns any buffered errors from lexing the initial -/// token stream; these must be consumed via `emit`, `cancel`, etc., otherwise a panic will occur -/// when they are dropped. -pub fn maybe_new_parser_from_source_str( +/// Creates a new parser from a source string. On failure, the errors must be consumed via +/// `unwrap_or_emit_fatal`, `emit`, `cancel`, etc., otherwise a panic will occur when they are +/// dropped. +pub fn new_parser_from_source_str( psess: &ParseSess, name: FileName, source: String, ) -> Result<Parser<'_>, Vec<Diag<'_>>> { - maybe_source_file_to_parser(psess, psess.source_map().new_source_file(name, source)) + let source_file = psess.source_map().new_source_file(name, source); + new_parser_from_source_file(psess, source_file) } -/// Creates a new parser, aborting if the file doesn't exist. If a span is given, that is used on -/// an error as the source of the problem. -pub fn new_parser_from_file<'a>(psess: &'a ParseSess, path: &Path, sp: Option<Span>) -> Parser<'a> { +/// Creates a new parser from a filename. On failure, the errors must be consumed via +/// `unwrap_or_emit_fatal`, `emit`, `cancel`, etc., otherwise a panic will occur when they are +/// dropped. +/// +/// If a span is given, that is used on an error as the source of the problem. +pub fn new_parser_from_file<'a>( + psess: &'a ParseSess, + path: &Path, + sp: Option<Span>, +) -> Result<Parser<'a>, Vec<Diag<'a>>> { let source_file = psess.source_map().load_file(path).unwrap_or_else(|e| { let msg = format!("couldn't read {}: {}", path.display(), e); let mut err = psess.dcx.struct_fatal(msg); @@ -120,40 +77,37 @@ pub fn new_parser_from_file<'a>(psess: &'a ParseSess, path: &Path, sp: Option<Sp } err.emit(); }); - - panictry_buffer!(maybe_source_file_to_parser(psess, source_file)) + new_parser_from_source_file(psess, source_file) } /// Given a session and a `source_file`, return a parser. Returns any buffered errors from lexing /// the initial token stream. -fn maybe_source_file_to_parser( +fn new_parser_from_source_file( psess: &ParseSess, source_file: Lrc<SourceFile>, ) -> Result<Parser<'_>, Vec<Diag<'_>>> { let end_pos = source_file.end_position(); - let stream = maybe_file_to_stream(psess, source_file, None)?; - let mut parser = stream_to_parser(psess, stream, None); + let stream = source_file_to_stream(psess, source_file, None)?; + let mut parser = Parser::new(psess, stream, None); if parser.token == token::Eof { parser.token.span = Span::new(end_pos, end_pos, parser.token.span.ctxt(), None); } - Ok(parser) } -// Base abstractions - -/// Given a `source_file`, produces a sequence of token trees. -pub fn source_file_to_stream( +pub fn source_str_to_stream( psess: &ParseSess, - source_file: Lrc<SourceFile>, + name: FileName, + source: String, override_span: Option<Span>, -) -> TokenStream { - panictry_buffer!(maybe_file_to_stream(psess, source_file, override_span)) +) -> Result<TokenStream, Vec<Diag<'_>>> { + let source_file = psess.source_map().new_source_file(name, source); + source_file_to_stream(psess, source_file, override_span) } /// Given a source file, produces a sequence of token trees. Returns any buffered errors from /// parsing the token stream. -fn maybe_file_to_stream<'psess>( +fn source_file_to_stream<'psess>( psess: &'psess ParseSess, source_file: Lrc<SourceFile>, override_span: Option<Span>, @@ -165,16 +119,7 @@ fn maybe_file_to_stream<'psess>( )); }); - lexer::parse_token_trees(psess, src.as_str(), source_file.start_pos, override_span) -} - -/// Given a stream and the `ParseSess`, produces a parser. -pub fn stream_to_parser<'a>( - psess: &'a ParseSess, - stream: TokenStream, - subparser_name: Option<&'static str>, -) -> Parser<'a> { - Parser::new(psess, stream, subparser_name) + lexer::lex_token_trees(psess, src.as_str(), source_file.start_pos, override_span) } /// Runs the given subparser `f` on the tokens of the given `attr`'s item. @@ -195,19 +140,28 @@ pub fn parse_in<'a, T>( pub fn fake_token_stream_for_item(psess: &ParseSess, item: &ast::Item) -> TokenStream { let source = pprust::item_to_string(item); let filename = FileName::macro_expansion_source_code(&source); - parse_stream_from_source_str(filename, source, psess, Some(item.span)) + unwrap_or_emit_fatal(source_str_to_stream(psess, filename, source, Some(item.span))) } pub fn fake_token_stream_for_crate(psess: &ParseSess, krate: &ast::Crate) -> TokenStream { let source = pprust::crate_to_string_for_macros(krate); let filename = FileName::macro_expansion_source_code(&source); - parse_stream_from_source_str(filename, source, psess, Some(krate.spans.inner_span)) + unwrap_or_emit_fatal(source_str_to_stream( + psess, + filename, + source, + Some(krate.spans.inner_span), + )) } pub fn parse_cfg_attr( attr: &Attribute, psess: &ParseSess, ) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> { + const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; + const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ + <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>"; + match attr.get_normal_item().args { ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens }) if !tokens.is_empty() => @@ -222,16 +176,12 @@ pub fn parse_cfg_attr( } } } - _ => error_malformed_cfg_attr_missing(attr.span, psess), + _ => { + psess.dcx.emit_err(errors::MalformedCfgAttr { + span: attr.span, + sugg: CFG_ATTR_GRAMMAR_HELP, + }); + } } None } - -const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]"; -const CFG_ATTR_NOTE_REF: &str = "for more information, visit \ - <https://doc.rust-lang.org/reference/conditional-compilation.html\ - #the-cfg_attr-attribute>"; - -fn error_malformed_cfg_attr_missing(span: Span, psess: &ParseSess) { - psess.dcx.emit_err(errors::MalformedCfgAttr { span, sugg: CFG_ATTR_GRAMMAR_HELP }); -} diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index a57eb70c705..58fef9b6c45 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -7,7 +7,7 @@ use rustc_ast as ast; use rustc_ast::attr; use rustc_ast::token::{self, Delimiter}; use rustc_errors::{codes::*, Diag, PResult}; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{sym, symbol::kw, BytePos, Span}; use thin_vec::ThinVec; use tracing::debug; @@ -252,9 +252,23 @@ impl<'a> Parser<'a> { maybe_whole!(self, NtMeta, |attr| attr.into_inner()); let do_parse = |this: &mut Self| { + let is_unsafe = this.eat_keyword(kw::Unsafe); + let unsafety = if is_unsafe { + let unsafe_span = this.prev_token.span; + this.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span); + this.expect(&token::OpenDelim(Delimiter::Parenthesis))?; + + ast::Safety::Unsafe(unsafe_span) + } else { + ast::Safety::Default + }; + let path = this.parse_path(PathStyle::Mod)?; let args = this.parse_attr_args()?; - Ok(ast::AttrItem { path, args, tokens: None }) + if is_unsafe { + this.expect(&token::CloseDelim(Delimiter::Parenthesis))?; + } + Ok(ast::AttrItem { unsafety, path, args, tokens: None }) }; // Attr items don't have attributes if capture_tokens { self.collect_tokens_no_attrs(do_parse) } else { do_parse(self) } @@ -265,7 +279,7 @@ impl<'a> Parser<'a> { /// terminated by a semicolon. /// /// Matches `inner_attrs*`. - pub(crate) fn parse_inner_attributes(&mut self) -> PResult<'a, ast::AttrVec> { + pub fn parse_inner_attributes(&mut self) -> PResult<'a, ast::AttrVec> { let mut attrs = ast::AttrVec::new(); loop { let start_pos: u32 = self.num_bump_calls.try_into().unwrap(); @@ -375,10 +389,25 @@ impl<'a> Parser<'a> { } let lo = self.token.span; + let is_unsafe = self.eat_keyword(kw::Unsafe); + let unsafety = if is_unsafe { + let unsafe_span = self.prev_token.span; + self.psess.gated_spans.gate(sym::unsafe_attributes, unsafe_span); + self.expect(&token::OpenDelim(Delimiter::Parenthesis))?; + + ast::Safety::Unsafe(unsafe_span) + } else { + ast::Safety::Default + }; + let path = self.parse_path(PathStyle::Mod)?; let kind = self.parse_meta_item_kind()?; + if is_unsafe { + self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; + } let span = lo.to(self.prev_token.span); - Ok(ast::MetaItem { path, kind, span }) + + Ok(ast::MetaItem { unsafety, path, kind, span }) } pub(crate) fn parse_meta_item_kind(&mut self) -> PResult<'a, ast::MetaItemKind> { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 9677eea0604..2bb6fb53869 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -130,14 +130,14 @@ pub enum AttemptLocalParseRecovery { } impl AttemptLocalParseRecovery { - pub fn yes(&self) -> bool { + pub(super) fn yes(&self) -> bool { match self { AttemptLocalParseRecovery::Yes => true, AttemptLocalParseRecovery::No => false, } } - pub fn no(&self) -> bool { + pub(super) fn no(&self) -> bool { match self { AttemptLocalParseRecovery::Yes => false, AttemptLocalParseRecovery::No => true, @@ -891,7 +891,7 @@ impl<'a> Parser<'a> { } } - pub fn maybe_suggest_struct_literal( + pub(super) fn maybe_suggest_struct_literal( &mut self, lo: Span, s: BlockCheckMode, @@ -2459,7 +2459,7 @@ impl<'a> Parser<'a> { /// Handle encountering a symbol in a generic argument list that is not a `,` or `>`. In this /// case, we emit an error and try to suggest enclosing a const argument in braces if it looks /// like the user has forgotten them. - pub fn handle_ambiguous_unbraced_const_arg( + pub(super) fn handle_ambiguous_unbraced_const_arg( &mut self, args: &mut ThinVec<AngleBracketedArg>, ) -> PResult<'a, bool> { @@ -2500,7 +2500,7 @@ impl<'a> Parser<'a> { /// - Single-segment paths (i.e. standalone generic const parameters). /// All other expressions that can be parsed will emit an error suggesting the expression be /// wrapped in braces. - pub fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, P<Expr>> { + pub(super) fn handle_unambiguous_unbraced_const_arg(&mut self) -> PResult<'a, P<Expr>> { let start = self.token.span; let expr = self.parse_expr_res(Restrictions::CONST_EXPR, None).map_err(|mut err| { err.span_label( @@ -2559,7 +2559,7 @@ impl<'a> Parser<'a> { Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })) } - pub fn recover_const_param_declaration( + pub(super) fn recover_const_param_declaration( &mut self, ty_generics: Option<&Generics>, ) -> PResult<'a, Option<GenericArg>> { @@ -2589,7 +2589,11 @@ impl<'a> Parser<'a> { /// When encountering code like `foo::< bar + 3 >` or `foo::< bar - baz >` we suggest /// `foo::<{ bar + 3 }>` and `foo::<{ bar - baz }>`, respectively. We only provide a suggestion /// if we think that the resulting expression would be well formed. - pub fn recover_const_arg(&mut self, start: Span, mut err: Diag<'a>) -> PResult<'a, GenericArg> { + pub(super) fn recover_const_arg( + &mut self, + start: Span, + mut err: Diag<'a>, + ) -> PResult<'a, GenericArg> { let is_op_or_dot = AssocOp::from_token(&self.token) .and_then(|op| { if let AssocOp::Greater @@ -2690,7 +2694,7 @@ impl<'a> Parser<'a> { } /// Creates a dummy const argument, and reports that the expression must be enclosed in braces - pub fn dummy_const_arg_needs_braces(&self, mut err: Diag<'a>, span: Span) -> GenericArg { + pub(super) fn dummy_const_arg_needs_braces(&self, mut err: Diag<'a>, span: Span) -> GenericArg { err.multipart_suggestion( "expressions must be enclosed in braces to be used as const generic \ arguments", @@ -2961,7 +2965,7 @@ impl<'a> Parser<'a> { /// * `=====` /// * `<<<<<` /// - pub fn is_vcs_conflict_marker( + pub(super) fn is_vcs_conflict_marker( &mut self, long_kind: &TokenKind, short_kind: &TokenKind, @@ -2981,14 +2985,14 @@ impl<'a> Parser<'a> { None } - pub fn recover_vcs_conflict_marker(&mut self) { + pub(super) fn recover_vcs_conflict_marker(&mut self) { if let Err(err) = self.err_vcs_conflict_marker() { err.emit(); FatalError.raise(); } } - pub fn err_vcs_conflict_marker(&mut self) -> PResult<'a, ()> { + pub(crate) fn err_vcs_conflict_marker(&mut self) -> PResult<'a, ()> { let Some(start) = self.conflict_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) else { return Ok(()); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1b99bc015b6..e15d6ab2123 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -328,9 +328,7 @@ impl<'a> Parser<'a> { this.parse_expr_assoc_with(prec + prec_adjustment, LhsExpr::NotYetParsed) })?; - self.error_ambiguous_outer_attrs(&lhs, lhs_span, rhs.span); - let span = lhs_span.to(rhs.span); - + let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span); lhs = match op { AssocOp::Add | AssocOp::Subtract @@ -429,23 +427,11 @@ impl<'a> Parser<'a> { }); } - fn error_ambiguous_outer_attrs(&self, lhs: &P<Expr>, lhs_span: Span, rhs_span: Span) { - if let Some(attr) = lhs.attrs.iter().find(|a| a.style == AttrStyle::Outer) { - self.dcx().emit_err(errors::AmbiguousOuterAttributes { - span: attr.span.to(rhs_span), - sugg: errors::WrapInParentheses::Expression { - left: attr.span.shrink_to_lo(), - right: lhs_span.shrink_to_hi(), - }, - }); - } - } - /// Possibly translate the current token to an associative operator. /// The method does not advance the current token. /// /// Also performs recovery for `and` / `or` which are mistaken for `&&` and `||` respectively. - pub fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> { + pub(super) fn check_assoc_op(&self) -> Option<Spanned<AssocOp>> { let (op, span) = match (AssocOp::from_token(&self.token), self.token.ident()) { // When parsing const expressions, stop parsing when encountering `>`. ( @@ -520,8 +506,7 @@ impl<'a> Parser<'a> { None }; let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span); - self.error_ambiguous_outer_attrs(&lhs, lhs.span, rhs_span); - let span = lhs.span.to(rhs_span); + let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span); let limits = if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed }; let range = self.mk_range(Some(lhs), rhs, limits); @@ -739,8 +724,7 @@ impl<'a> Parser<'a> { expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind, ) -> PResult<'a, P<Expr>> { let mk_expr = |this: &mut Self, lhs: P<Expr>, rhs: P<Ty>| { - this.error_ambiguous_outer_attrs(&lhs, lhs_span, rhs.span); - this.mk_expr(lhs_span.to(rhs.span), expr_kind(lhs, rhs)) + this.mk_expr(this.mk_expr_sp(&lhs, lhs_span, rhs.span), expr_kind(lhs, rhs)) }; // Save the state of the parser before parsing type normally, in case there is a @@ -1022,7 +1006,11 @@ impl<'a> Parser<'a> { } } - pub fn parse_dot_suffix_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> { + pub(super) fn parse_dot_suffix_expr( + &mut self, + lo: Span, + base: P<Expr>, + ) -> PResult<'a, P<Expr>> { // At this point we've consumed something like `expr.` and `self.token` holds the token // after the dot. match self.token.uninterpolate().kind { @@ -3858,6 +3846,16 @@ impl<'a> Parser<'a> { self.mk_expr(span, ExprKind::Err(guar)) } + /// Create expression span ensuring the span of the parent node + /// is larger than the span of lhs and rhs, including the attributes. + fn mk_expr_sp(&self, lhs: &P<Expr>, lhs_span: Span, rhs_span: Span) -> Span { + lhs.attrs + .iter() + .find(|a| a.style == AttrStyle::Outer) + .map_or(lhs_span, |a| a.span) + .to(rhs_span) + } + fn collect_tokens_for_expr( &mut self, attrs: AttrWrapper, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 53757c38e8b..3f5a4afdad8 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -226,10 +226,11 @@ impl<'a> Parser<'a> { self.expect_keyword(kw::Extern)?; self.parse_item_foreign_mod(attrs, safety)? } else if self.is_static_global() { + let safety = self.parse_safety(Case::Sensitive); // STATIC ITEM self.bump(); // `static` let mutability = self.parse_mutability(); - let (ident, item) = self.parse_static_item(mutability)?; + let (ident, item) = self.parse_static_item(safety, mutability)?; (ident, ItemKind::Static(Box::new(item))) } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) { // CONST ITEM @@ -952,7 +953,7 @@ impl<'a> Parser<'a> { let kind = match AssocItemKind::try_from(kind) { Ok(kind) => kind, Err(kind) => match kind { - ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => { + ItemKind::Static(box StaticItem { ty, safety: _, mutability: _, expr }) => { self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span }); AssocItemKind::Const(Box::new(ConstItem { defaultness: Defaultness::Final, @@ -1221,6 +1222,7 @@ impl<'a> Parser<'a> { ty, mutability: Mutability::Not, expr, + safety: Safety::Default, })) } _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), @@ -1258,7 +1260,10 @@ impl<'a> Parser<'a> { matches!(token.kind, token::BinOp(token::Or) | token::OrOr) }) } else { - false + let quals: &[Symbol] = &[kw::Unsafe, kw::Safe]; + // `$qual static` + quals.iter().any(|&kw| self.check_keyword(kw)) + && self.look_ahead(1, |t| t.is_keyword(kw::Static)) } } @@ -1319,7 +1324,11 @@ impl<'a> Parser<'a> { /// ```ebnf /// Static = "static" "mut"? $ident ":" $ty (= $expr)? ";" ; /// ``` - fn parse_static_item(&mut self, mutability: Mutability) -> PResult<'a, (Ident, StaticItem)> { + fn parse_static_item( + &mut self, + safety: Safety, + mutability: Mutability, + ) -> PResult<'a, (Ident, StaticItem)> { let ident = self.parse_ident()?; if self.token.kind == TokenKind::Lt && self.may_recover() { @@ -1340,7 +1349,7 @@ impl<'a> Parser<'a> { self.expect_semi()?; - Ok((ident, StaticItem { ty, mutability, expr })) + Ok((ident, StaticItem { ty, safety, mutability, expr })) } /// Parse a constant item with the prefix `"const"` already parsed. @@ -2256,7 +2265,7 @@ pub(crate) struct FnParseMode { /// to true. /// * The span is from Edition 2015. In particular, you can get a /// 2015 span inside a 2021 crate using macros. - pub req_name: ReqName, + pub(super) req_name: ReqName, /// If this flag is set to `true`, then plain, semicolon-terminated function /// prototypes are not allowed here. /// @@ -2275,7 +2284,7 @@ pub(crate) struct FnParseMode { /// This field should only be set to false if the item is inside of a trait /// definition or extern block. Within an impl block or a module, it should /// always be set to true. - pub req_body: bool, + pub(super) req_body: bool, } /// Parsing of functions and methods. @@ -2400,9 +2409,9 @@ impl<'a> Parser<'a> { // `pub` is added in case users got confused with the ordering like `async pub fn`, // only if it wasn't preceded by `default` as `default pub` is invalid. let quals: &[Symbol] = if check_pub { - &[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Extern] + &[kw::Pub, kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Safe, kw::Extern] } else { - &[kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Extern] + &[kw::Gen, kw::Const, kw::Async, kw::Unsafe, kw::Safe, kw::Extern] }; self.check_keyword_case(kw::Fn, case) // Definitely an `fn`. // `$qual fn` or `$qual $qual`: @@ -2537,11 +2546,27 @@ impl<'a> Parser<'a> { } else if self.check_keyword(kw::Unsafe) { match safety { Safety::Unsafe(sp) => Some(WrongKw::Duplicated(sp)), + Safety::Safe(sp) => { + recover_safety = Safety::Unsafe(self.token.span); + Some(WrongKw::Misplaced(sp)) + } Safety::Default => { recover_safety = Safety::Unsafe(self.token.span); Some(WrongKw::Misplaced(ext_start_sp)) } } + } else if self.check_keyword(kw::Safe) { + match safety { + Safety::Safe(sp) => Some(WrongKw::Duplicated(sp)), + Safety::Unsafe(sp) => { + recover_safety = Safety::Safe(self.token.span); + Some(WrongKw::Misplaced(sp)) + } + Safety::Default => { + recover_safety = Safety::Safe(self.token.span); + Some(WrongKw::Misplaced(ext_start_sp)) + } + } } else { None }; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index bab8b6c06eb..adf04fcf224 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -11,22 +11,21 @@ mod stmt; mod ty; use crate::lexer::UnmatchedDelim; -pub use attr_wrapper::AttrWrapper; +use attr_wrapper::AttrWrapper; pub use diagnostics::AttemptLocalParseRecovery; pub(crate) use expr::ForbiddenLetReason; pub(crate) use item::FnParseMode; pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; -pub use path::PathStyle; +use path::PathStyle; -use core::fmt; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing}; use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor}; use rustc_ast::util::case::Case; use rustc_ast::{ - self as ast, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, DelimArgs, Expr, - ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, Visibility, + self as ast, AnonConst, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, DelimArgs, + Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, Visibility, VisibilityKind, DUMMY_NODE_ID, }; use rustc_ast_pretty::pprust; @@ -37,7 +36,7 @@ use rustc_session::parse::ParseSess; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use std::ops::Range; -use std::{mem, slice}; +use std::{fmt, mem, slice}; use thin_vec::ThinVec; use tracing::debug; @@ -146,7 +145,7 @@ pub struct Parser<'a> { /// The current token. pub token: Token, /// The spacing for the current token. - pub token_spacing: Spacing, + token_spacing: Spacing, /// The previous token. pub prev_token: Token, pub capture_cfg: bool, @@ -187,7 +186,7 @@ pub struct Parser<'a> { current_closure: Option<ClosureSpans>, /// Whether the parser is allowed to do recovery. /// This is disabled when parsing macro arguments, see #103534 - pub recovery: Recovery, + recovery: Recovery, } // This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure @@ -197,10 +196,10 @@ rustc_data_structures::static_assert_size!(Parser<'_>, 264); /// Stores span information about a closure. #[derive(Clone, Debug)] -pub struct ClosureSpans { - pub whole_closure: Span, - pub closing_pipe: Span, - pub body: Span, +struct ClosureSpans { + whole_closure: Span, + closing_pipe: Span, + body: Span, } /// Indicates a range of tokens that should be replaced by @@ -220,13 +219,13 @@ pub struct ClosureSpans { /// the first macro inner attribute to invoke a proc-macro). /// When create a `TokenStream`, the inner attributes get inserted /// into the proper place in the token stream. -pub type ReplaceRange = (Range<u32>, Vec<(FlatToken, Spacing)>); +type ReplaceRange = (Range<u32>, 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, Debug)] -pub enum Capturing { +enum Capturing { /// We aren't performing any capturing - this is the default mode. No, /// We are capturing tokens @@ -374,13 +373,13 @@ pub enum FollowedByType { } #[derive(Copy, Clone, Debug)] -pub enum Trailing { +enum Trailing { No, Yes, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum TokenDescription { +pub(super) enum TokenDescription { ReservedIdentifier, Keyword, ReservedKeyword, @@ -388,7 +387,7 @@ pub enum TokenDescription { } impl TokenDescription { - pub fn from_token(token: &Token) -> Option<Self> { + pub(super) fn from_token(token: &Token) -> Option<Self> { match token.kind { _ if token.is_special_ident() => Some(TokenDescription::ReservedIdentifier), _ if token.is_used_keyword() => Some(TokenDescription::Keyword), @@ -502,7 +501,7 @@ impl<'a> Parser<'a> { /// Expect next token to be edible or inedible token. If edible, /// then consume it; if inedible, then return without consuming /// anything. Signal a fatal error if next token is unexpected. - pub fn expect_one_of( + fn expect_one_of( &mut self, edible: &[TokenKind], inedible: &[TokenKind], @@ -572,7 +571,7 @@ impl<'a> Parser<'a> { /// the main purpose of this function is to reduce the cluttering of the suggestions list /// which using the normal eat method could introduce in some cases. #[inline] - pub fn eat_noexpect(&mut self, tok: &TokenKind) -> bool { + fn eat_noexpect(&mut self, tok: &TokenKind) -> bool { let is_present = self.check_noexpect(tok); if is_present { self.bump() @@ -1221,6 +1220,8 @@ impl<'a> Parser<'a> { fn parse_safety(&mut self, case: Case) -> Safety { if self.eat_keyword_case(kw::Unsafe, case) { Safety::Unsafe(self.prev_token.uninterpolated_span()) + } else if self.eat_keyword_case(kw::Safe, case) { + Safety::Safe(self.prev_token.uninterpolated_span()) } else { Safety::Default } @@ -1260,9 +1261,12 @@ impl<'a> Parser<'a> { } self.eat_keyword(kw::Const); let (attrs, blk) = self.parse_inner_attrs_and_block()?; - let expr = self.mk_expr(blk.span, ExprKind::Block(blk, None)); - let blk_span = expr.span; - Ok(self.mk_expr_with_attrs(span.to(blk_span), ExprKind::ConstBlock(expr), attrs)) + let anon_const = AnonConst { + id: DUMMY_NODE_ID, + value: self.mk_expr(blk.span, ExprKind::Block(blk, None)), + }; + let blk_span = anon_const.value.span; + Ok(self.mk_expr_with_attrs(span.to(blk_span), ExprKind::ConstBlock(anon_const), attrs)) } /// Parses mutability (`mut` or nothing). @@ -1515,7 +1519,7 @@ impl<'a> Parser<'a> { } } - pub fn collect_tokens_no_attrs<R: HasAttrs + HasTokens>( + fn collect_tokens_no_attrs<R: HasAttrs + HasTokens>( &mut self, f: impl FnOnce(&mut Self) -> PResult<'a, R>, ) -> PResult<'a, R> { @@ -1536,8 +1540,10 @@ 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 + '_ { + // Debug view of the parser's token stream, up to `{lookahead}` tokens. + // Only used when debugging. + #[allow(unused)] + pub(crate) fn debug_lookahead(&self, lookahead: usize) -> impl fmt::Debug + '_ { struct DebugParser<'dbg> { parser: &'dbg Parser<'dbg>, lookahead: usize, @@ -1613,7 +1619,7 @@ pub(crate) fn make_unclosed_delims_error( /// is then 'parsed' to build up an `AttrTokenStream` with nested /// `AttrTokenTree::Delimited` tokens. #[derive(Debug, Clone)] -pub enum FlatToken { +enum FlatToken { /// A token - this holds both delimiter (e.g. '{' and '}') /// and non-delimiter tokens Token(Token), diff --git a/compiler/rustc_parse/src/parser/mut_visit/tests.rs b/compiler/rustc_parse/src/parser/mut_visit/tests.rs index b3cb28af657..677bcdf7fcd 100644 --- a/compiler/rustc_parse/src/parser/mut_visit/tests.rs +++ b/compiler/rustc_parse/src/parser/mut_visit/tests.rs @@ -21,14 +21,12 @@ impl MutVisitor for ToZzIdentMutVisitor { } } -// Maybe add to `expand.rs`. -macro_rules! assert_pred { - ($pred:expr, $predname:expr, $a:expr , $b:expr) => {{ - let pred_val = $pred; +macro_rules! assert_matches_codepattern { + ($a:expr , $b:expr) => {{ let a_val = $a; let b_val = $b; - if !(pred_val(&a_val, &b_val)) { - panic!("expected args satisfying {}, got {} and {}", $predname, a_val, b_val); + if !matches_codepattern(&a_val, &b_val) { + panic!("expected args satisfying `matches_codepattern`, got {} and {}", a_val, b_val); } }}; } @@ -41,9 +39,7 @@ fn ident_transformation() { let mut krate = string_to_crate("#[a] mod b {fn c (d : e, f : g) {h!(i,j,k);l;m}}".to_string()); zz_visitor.visit_crate(&mut krate); - assert_pred!( - matches_codepattern, - "matches_codepattern", + assert_matches_codepattern!( print_crate_items(&krate), "#[zz]mod zz{fn zz(zz:zz,zz:zz){zz!(zz,zz,zz);zz;zz}}".to_string() ); @@ -61,9 +57,7 @@ fn ident_transformation_in_defs() { .to_string(), ); zz_visitor.visit_crate(&mut krate); - assert_pred!( - matches_codepattern, - "matches_codepattern", + assert_matches_codepattern!( print_crate_items(&krate), "macro_rules! zz{(zz$zz:zz$(zz $zz:zz)zz+=>(zz$(zz$zz$zz)+))}".to_string() ); diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index fcedc1a4af3..9beecd9849f 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -20,7 +20,7 @@ use tracing::debug; /// Specifies how to parse a path. #[derive(Copy, Clone, PartialEq)] -pub enum PathStyle { +pub(super) enum PathStyle { /// In some contexts, notably in expressions, paths with generic arguments are ambiguous /// with something else. For example, in expressions `segment < ....` can be interpreted /// as a comparison and `segment ( ....` can be interpreted as a function call. diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index be539d15386..104aae9b257 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -31,7 +31,7 @@ impl<'a> Parser<'a> { /// Parses a statement. This stops just before trailing semicolons on everything but items. /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed. // Public for rustfmt usage. - pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Stmt>> { + pub(super) fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Stmt>> { Ok(self.parse_stmt_without_recovery(false, force_collect).unwrap_or_else(|e| { e.emit(); self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index a31e350541a..79a6cf1b541 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -1,5 +1,7 @@ use crate::parser::ForceCollect; -use crate::{new_parser_from_source_str, parser::Parser, source_file_to_stream}; +use crate::{ + new_parser_from_source_str, parser::Parser, source_str_to_stream, unwrap_or_emit_fatal, +}; use ast::token::IdentIsRaw; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token}; @@ -29,7 +31,11 @@ fn psess() -> ParseSess { /// Map string to parser (via tts). fn string_to_parser(psess: &ParseSess, source_str: String) -> Parser<'_> { - new_parser_from_source_str(psess, PathBuf::from("bogofile").into(), source_str) + unwrap_or_emit_fatal(new_parser_from_source_str( + psess, + PathBuf::from("bogofile").into(), + source_str, + )) } fn create_test_handler() -> (DiagCtxt, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) { @@ -82,11 +88,12 @@ where /// Maps a string to tts, using a made-up filename. pub(crate) fn string_to_stream(source_str: String) -> TokenStream { let psess = psess(); - source_file_to_stream( + unwrap_or_emit_fatal(source_str_to_stream( &psess, - psess.source_map().new_source_file(PathBuf::from("bogofile").into(), source_str), + PathBuf::from("bogofile").into(), + source_str, None, - ) + )) } /// Parses a string, returns a crate. @@ -1068,7 +1075,8 @@ fn parse_item_from_source_str( source: String, psess: &ParseSess, ) -> PResult<'_, Option<P<ast::Item>>> { - new_parser_from_source_str(psess, name, source).parse_item(ForceCollect::No) + unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source)) + .parse_item(ForceCollect::No) } // Produces a `rustc_span::span`. @@ -1349,7 +1357,7 @@ fn ttdelim_span() { source: String, psess: &ParseSess, ) -> PResult<'_, P<ast::Expr>> { - new_parser_from_source_str(psess, name, source).parse_expr() + unwrap_or_emit_fatal(new_parser_from_source_str(psess, name, source)).parse_expr() } create_default_session_globals_then(|| { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 2033f387887..5bed0317e5e 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -127,7 +127,7 @@ impl<'a> Parser<'a> { /// Parse a type suitable for a field definition. /// The difference from `parse_ty` is that this version /// allows anonymous structs and unions. - pub fn parse_ty_for_field_def(&mut self) -> PResult<'a, P<Ty>> { + pub(super) fn parse_ty_for_field_def(&mut self) -> PResult<'a, P<Ty>> { if self.can_begin_anon_struct_or_union() { self.parse_anon_struct_or_union() } else { diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index b91ef1ae1f3..19d6f512572 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -25,15 +25,21 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) { match attr_info { // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => { - check_builtin_attribute(psess, attr, *name, *template) + match parse_meta(psess, attr) { + Ok(meta) => check_builtin_meta_item(psess, &meta, attr.style, *name, *template), + Err(err) => { + err.emit(); + } + } } _ if let AttrArgs::Eq(..) = attr.get_normal_item().args => { // All key-value attributes are restricted to meta-item syntax. - parse_meta(psess, attr) - .map_err(|err| { + match parse_meta(psess, attr) { + Ok(_) => {} + Err(err) => { err.emit(); - }) - .ok(); + } + } } _ => {} } @@ -42,6 +48,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) { pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> { let item = attr.get_normal_item(); Ok(MetaItem { + unsafety: item.unsafety, span: attr.span, path: item.path.clone(), kind: match &item.args { @@ -103,7 +110,7 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met }) } -pub fn check_meta_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) { +fn check_meta_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) { if let Delimiter::Parenthesis = delim { return; } @@ -113,7 +120,7 @@ pub fn check_meta_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter }); } -pub fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) { +pub(super) fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) { if let Delimiter::Parenthesis = delim { return; } @@ -133,20 +140,6 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte } } -pub fn check_builtin_attribute( - psess: &ParseSess, - attr: &Attribute, - name: Symbol, - template: AttributeTemplate, -) { - match parse_meta(psess, attr) { - Ok(meta) => check_builtin_meta_item(psess, &meta, attr.style, name, template), - Err(err) => { - err.emit(); - } - } -} - pub fn check_builtin_meta_item( psess: &ParseSess, meta: &MetaItem, diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index d850644bb45..07c82065a80 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -384,6 +384,10 @@ passes_invalid_attr_at_crate_level = passes_invalid_attr_at_crate_level_item = the inner attribute doesn't annotate this {$kind} +passes_invalid_attr_unsafe = `{$name}` is not an unsafe attribute + .suggestion = remove the `unsafe(...)` + .note = extraneous unsafe is not allowed in attributes + passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 4fe84b91b8b..6ce7c41acc8 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,7 +10,9 @@ use rustc_ast::{MetaItemKind, MetaItemLit, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::StashKey; use rustc_errors::{Applicability, DiagCtxt, IntoDiagArg, MultiSpan}; -use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; +use rustc_feature::{ + is_unsafe_attr, AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP, +}; use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir}; @@ -114,6 +116,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut seen = FxHashMap::default(); let attrs = self.tcx.hir().attrs(hir_id); for attr in attrs { + self.check_unsafe_attr(attr); + match attr.path().as_slice() { [sym::diagnostic, sym::do_not_recommend] => { self.check_do_not_recommend(attr.span, hir_id, target) @@ -308,6 +312,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> { true } + /// Checks if `unsafe()` is applied to an invalid attribute. + fn check_unsafe_attr(&self, attr: &Attribute) { + if !attr.is_doc_comment() { + let attr_item = attr.get_normal_item(); + if let ast::Safety::Unsafe(unsafe_span) = attr_item.unsafety { + if !is_unsafe_attr(attr.name_or_empty()) { + self.dcx().emit_err(errors::InvalidAttrUnsafe { + span: unsafe_span, + name: attr_item.path.clone(), + }); + } + } + } + } + /// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition fn check_diagnostic_on_unimplemented( &self, @@ -2321,7 +2340,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let param_env = ty::ParamEnv::empty(); let infcx = tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let span = tcx.def_span(def_id); let fresh_args = infcx.fresh_args_for_item(span, def_id.to_def_id()); diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 71f3e8b7b5d..3f6eccbd5a5 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -196,6 +196,11 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon)); } + fn visit_inline_const(&mut self, block: &'tcx hir::ConstBlock) { + let kind = Some(hir::ConstContext::Const { inline: true }); + self.recurse_into(kind, None, |this| intravisit::walk_inline_const(this, block)); + } + fn visit_body(&mut self, body: &hir::Body<'tcx>) { let owner = self.tcx.hir().body_owner_def_id(body.id()); let kind = self.tcx.hir().body_const_context(owner); @@ -223,11 +228,6 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { self.const_check_violated(expr, e.span); } } - hir::ExprKind::ConstBlock(expr) => { - let kind = Some(hir::ConstContext::Const { inline: true }); - self.recurse_into(kind, None, |this| intravisit::walk_expr(this, expr)); - return; - } _ => {} } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 0049afff528..2cb3c5d8965 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -15,7 +15,7 @@ use rustc_hir::{Node, PatKind, TyKind}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy::Level; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, AssocItemContainer, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_session::lint::builtin::DEAD_CODE; @@ -44,16 +44,63 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { ) } -fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> bool { +struct Publicness { + ty_is_public: bool, + ty_and_all_fields_are_public: bool, +} + +impl Publicness { + fn new(ty_is_public: bool, ty_and_all_fields_are_public: bool) -> Self { + Self { ty_is_public, ty_and_all_fields_are_public } + } +} + +fn struct_all_fields_are_public(tcx: TyCtxt<'_>, id: DefId) -> bool { + // treat PhantomData and positional ZST as public, + // we don't want to lint types which only have them, + // cause it's a common way to use such types to check things like well-formedness + tcx.adt_def(id).all_fields().all(|field| { + let field_type = tcx.type_of(field.did).instantiate_identity(); + if field_type.is_phantom_data() { + return true; + } + let is_positional = field.name.as_str().starts_with(|c: char| c.is_ascii_digit()); + if is_positional + && tcx + .layout_of(tcx.param_env(field.did).and(field_type)) + .map_or(true, |layout| layout.is_zst()) + { + return true; + } + field.vis.is_public() + }) +} + +/// check struct and its fields are public or not, +/// for enum and union, just check they are public, +/// and doesn't solve types like &T for now, just skip them +fn ty_ref_to_pub_struct(tcx: TyCtxt<'_>, ty: &hir::Ty<'_>) -> Publicness { if let TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind && let Res::Def(def_kind, def_id) = path.res && def_id.is_local() - && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union) { - tcx.visibility(def_id).is_public() - } else { - true + return match def_kind { + DefKind::Enum | DefKind::Union => { + let ty_is_public = tcx.visibility(def_id).is_public(); + Publicness::new(ty_is_public, ty_is_public) + } + DefKind::Struct => { + let ty_is_public = tcx.visibility(def_id).is_public(); + Publicness::new( + ty_is_public, + ty_is_public && struct_all_fields_are_public(tcx, def_id), + ) + } + _ => Publicness::new(true, true), + }; } + + Publicness::new(true, true) } /// Determine if a work from the worklist is coming from the a `#[allow]` @@ -427,9 +474,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { { if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) && !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty) + .ty_and_all_fields_are_public { - // skip methods of private ty, - // they would be solved in `solve_rest_impl_items` + // skip impl-items of non pure pub ty, + // cause we don't know the ty is constructed or not, + // check these later in `solve_rest_impl_items` continue; } @@ -510,22 +559,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { && let Some(local_def_id) = def_id.as_local() && matches!(def_kind, DefKind::Struct | DefKind::Enum | DefKind::Union) { - if self.tcx.visibility(impl_item_id).is_public() { - // for the public method, we don't know the trait item is used or not, - // so we mark the method live if the self is used - return self.live_symbols.contains(&local_def_id); - } - if let Some(trait_item_id) = self.tcx.associated_item(impl_item_id).trait_item_def_id && let Some(local_id) = trait_item_id.as_local() { - // for the private method, we can know the trait item is used or not, + // for the local impl item, we can know the trait item is used or not, // so we mark the method live if the self is used and the trait item is used - return self.live_symbols.contains(&local_id) - && self.live_symbols.contains(&local_def_id); + self.live_symbols.contains(&local_id) && self.live_symbols.contains(&local_def_id) + } else { + // for the foreign method and inherent pub method, + // we don't know the trait item or the method is used or not, + // so we mark the method live if the self is used + self.live_symbols.contains(&local_def_id) } + } else { + false } - false } } @@ -587,16 +635,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { hir::ExprKind::OffsetOf(..) => { self.handle_offset_of(expr); } - hir::ExprKind::ConstBlock(expr) => { - // When inline const blocks are used in pattern position, paths - // referenced by it should be considered as used. - let in_pat = mem::replace(&mut self.in_pat, false); - - intravisit::walk_expr(self, expr); - - self.in_pat = in_pat; - return; - } _ => (), } @@ -658,6 +696,17 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { self.in_pat = in_pat; } + + fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) { + // When inline const blocks are used in pattern position, paths + // referenced by it should be considered as used. + let in_pat = mem::replace(&mut self.in_pat, false); + + self.live_symbols.insert(c.def_id); + intravisit::walk_inline_const(self, c); + + self.in_pat = in_pat; + } } fn has_allow_dead_code_or_lang_attr( @@ -746,7 +795,9 @@ fn check_item<'tcx>( .iter() .filter_map(|def_id| def_id.as_local()); - let ty_is_pub = ty_ref_to_pub_struct(tcx, tcx.hir().item(id).expect_impl().self_ty); + let self_ty = tcx.hir().item(id).expect_impl().self_ty; + let Publicness { ty_is_public, ty_and_all_fields_are_public } = + ty_ref_to_pub_struct(tcx, self_ty); // And we access the Map here to get HirId from LocalDefId for local_def_id in local_def_ids { @@ -762,18 +813,20 @@ fn check_item<'tcx>( // for trait impl blocks, // mark the method live if the self_ty is public, // or the method is public and may construct self - if of_trait - && (!matches!(tcx.def_kind(local_def_id), DefKind::AssocFn) - || tcx.visibility(local_def_id).is_public() - && (ty_is_pub || may_construct_self)) + if of_trait && matches!(tcx.def_kind(local_def_id), DefKind::AssocTy) + || tcx.visibility(local_def_id).is_public() + && (ty_and_all_fields_are_public || may_construct_self) { + // if the impl item is public, + // and the ty may be constructed or can be constructed in foreign crates, + // mark the impl item live worklist.push((local_def_id, ComesFromAllowExpect::No)); } else if let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, local_def_id) { worklist.push((local_def_id, comes_from_allow)); - } else if of_trait { - // private method || public method not constructs self + } else if of_trait || tcx.visibility(local_def_id).is_public() && ty_is_public { + // private impl items of traits || public impl items not constructs self unsolved_impl_items.push((id, local_def_id)); } } @@ -840,6 +893,14 @@ fn create_and_seed_worklist( effective_vis .is_public_at_level(Level::Reachable) .then_some(id) + .filter(|&id| + // checks impls, impl-items and pub structs with all public fields later + match tcx.def_kind(id) { + DefKind::Impl { .. } => false, + DefKind::AssocConst | DefKind::AssocFn => !matches!(tcx.associated_item(id).container, AssocItemContainer::ImplContainer), + DefKind::Struct => struct_all_fields_are_public(tcx, id.to_def_id()), + _ => true + }) .map(|id| (id, ComesFromAllowExpect::No)) }) // Seed entry point @@ -1112,10 +1173,15 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { || (def_kind == DefKind::Trait && live_symbols.contains(&item.owner_id.def_id)) { for &def_id in tcx.associated_item_def_ids(item.owner_id.def_id) { - // We have diagnosed unused methods in traits + // We have diagnosed unused assoc consts and fns in traits if matches!(def_kind, DefKind::Impl { of_trait: true }) - && tcx.def_kind(def_id) == DefKind::AssocFn - || def_kind == DefKind::Trait && tcx.def_kind(def_id) != DefKind::AssocFn + && matches!(tcx.def_kind(def_id), DefKind::AssocConst | DefKind::AssocFn) + // skip unused public inherent methods, + // cause we have diagnosed unconstructed struct + || matches!(def_kind, DefKind::Impl { of_trait: false }) + && tcx.visibility(def_id).is_public() + && ty_ref_to_pub_struct(tcx, tcx.hir().item(item).expect_impl().self_ty).ty_is_public + || def_kind == DefKind::Trait && tcx.def_kind(def_id) == DefKind::AssocTy { continue; } diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index 78653e5f95a..906ecdfe5ab 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -82,7 +82,7 @@ fn all_diagnostic_items(tcx: TyCtxt<'_>, (): ()) -> DiagnosticItems { let mut items = DiagnosticItems::default(); // Collect diagnostic items in other crates. - for &cnum in tcx.crates_including_speculative(()).iter().chain(std::iter::once(&LOCAL_CRATE)) { + for &cnum in tcx.crates(()).iter().chain(std::iter::once(&LOCAL_CRATE)) { for (&name, &def_id) in &tcx.diagnostic_items(cnum).name_to_id { collect_item(tcx, &mut items, name, def_id); } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 7fdd9924b51..a935f1ad7d3 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -4,7 +4,7 @@ use std::{ }; use crate::fluent_generated as fluent; -use rustc_ast::Label; +use rustc_ast::{ast, Label}; use rustc_errors::{ codes::*, Applicability, Diag, DiagCtxt, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic, @@ -863,6 +863,15 @@ pub struct InvalidAttrAtCrateLevel { pub item: Option<ItemFollowingInnerAttr>, } +#[derive(Diagnostic)] +#[diag(passes_invalid_attr_unsafe)] +#[note] +pub struct InvalidAttrUnsafe { + #[primary_span] + pub span: Span, + pub name: ast::Path, +} + #[derive(Clone, Copy)] pub struct ItemFollowingInnerAttr { pub span: Span, diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 82d43f078ee..c9a47650456 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -54,7 +54,7 @@ pub fn ensure_wf<'tcx>( pred, ); let infcx = tcx.infer_ctxt().build(); - let ocx = traits::ObligationCtxt::new(&infcx); + let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); ocx.register_obligation(obligation); let errors = ocx.select_all_or_error(); if !errors.is_empty() { diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 698f15015c4..dfa7dfa3398 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -147,11 +147,6 @@ fn check_liveness(tcx: TyCtxt<'_>, def_id: LocalDefId) { return; } - // Don't run for inline consts, they are collected together with their parent - if let DefKind::InlineConst = tcx.def_kind(def_id) { - return; - } - // Don't run unused pass for #[naked] if tcx.has_attr(def_id.to_def_id(), sym::naked) { return; @@ -1148,13 +1143,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprKind::Lit(..) + | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Err(_) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) | hir::ExprKind::Path(hir::QPath::LangItem(..)) | hir::ExprKind::OffsetOf(..) => succ, - hir::ExprKind::ConstBlock(expr) => self.propagate_through_expr(expr, succ), - // Note that labels have been resolved, so we don't need to look // at the label ident hir::ExprKind::Block(ref blk, _) => self.propagate_through_block(blk, succ), diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 737310e5c04..2587a18b8c8 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -93,6 +93,10 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { self.with_context(Constant, |v| intravisit::walk_anon_const(v, c)); } + fn visit_inline_const(&mut self, c: &'hir hir::ConstBlock) { + self.with_context(Constant, |v| intravisit::walk_inline_const(v, c)); + } + fn visit_fn( &mut self, fk: hir::intravisit::FnKind<'hir>, @@ -285,9 +289,6 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { self.cx_stack.len() - 1, ) } - hir::ExprKind::ConstBlock(expr) => { - self.with_context(Constant, |v| intravisit::walk_expr(v, expr)); - } _ => intravisit::walk_expr(self, e), } } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index ab1dd248556..6dd8eaf7e67 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -32,7 +32,7 @@ use rustc_hir::Node; use rustc_middle::bug; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::middle::privacy::{self, Level}; -use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc}; +use rustc_middle::mir::interpret::{ConstAllocation, ErrorHandled, GlobalAlloc}; use rustc_middle::query::Providers; use rustc_middle::ty::{self, ExistentialTraitRef, TyCtxt}; use rustc_privacy::DefIdVisitor; @@ -157,6 +157,7 @@ impl<'tcx> ReachableContext<'tcx> { } hir::ImplItemKind::Type(_) => false, }, + Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => true, _ => false, } } @@ -205,11 +206,24 @@ impl<'tcx> ReachableContext<'tcx> { } } - // Reachable constants will be inlined into other crates - // unconditionally, so we need to make sure that their - // contents are also reachable. hir::ItemKind::Const(_, _, init) => { - self.visit_nested_body(init); + // Only things actually ending up in the final constant value are reachable + // for codegen. Everything else is only needed during const-eval, so even if + // const-eval happens in a downstream crate, all they need is + // `mir_for_ctfe`. + match self.tcx.const_eval_poly_to_alloc(item.owner_id.def_id.into()) { + Ok(alloc) => { + let alloc = self.tcx.global_alloc(alloc.alloc_id).unwrap_memory(); + self.propagate_from_alloc(alloc); + } + // We can't figure out which value the constant will evaluate to. In + // lieu of that, we have to consider everything mentioned in the const + // initializer reachable, since it *may* end up in the final value. + Err(ErrorHandled::TooGeneric(_)) => self.visit_nested_body(init), + // If there was an error evaluating the const, nothing can be reachable + // via it, and anyway compilation will fail. + Err(ErrorHandled::Reported(..)) => {} + } } hir::ItemKind::Static(..) => { if let Ok(alloc) = self.tcx.eval_static_initializer(item.owner_id.def_id) { diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 31c709f2eb6..6bdfaf0c908 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -1020,7 +1020,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { // stabilization diagnostic, but it can be avoided when there are no // `remaining_lib_features`. let mut all_implications = remaining_implications.clone(); - for &cnum in tcx.used_crates(()) { + for &cnum in tcx.crates(()) { all_implications .extend_unord(tcx.stability_implications(cnum).items().map(|(k, v)| (*k, *v))); } @@ -1033,7 +1033,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { &all_implications, ); - for &cnum in tcx.used_crates(()) { + for &cnum in tcx.crates(()) { if remaining_lib_features.is_empty() && remaining_implications.is_empty() { break; } diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index d80addf1236..90691ca1790 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -68,7 +68,7 @@ fn verify(tcx: TyCtxt<'_>, items: &lang_items::LanguageItems) { } let mut missing = FxHashSet::default(); - for &cnum in tcx.used_crates(()).iter() { + for &cnum in tcx.crates(()).iter() { for &item in tcx.missing_lang_items(cnum).iter() { missing.insert(item); } diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index ff68dd81bea..8391c694c64 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -6,11 +6,12 @@ use rustc_hir::def_id::DefId; use rustc_hir::HirId; use rustc_index::{Idx, IndexVec}; use rustc_middle::middle::stability::EvalResult; -use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::{self, Const}; use rustc_middle::thir::{self, FieldPat, Pat, PatKind, PatRange, PatRangeBoundary}; use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::{self, FieldDef, OpaqueTypeKey, Ty, TyCtxt, TypeVisitableExt, VariantDef}; +use rustc_middle::ty::{ + self, FieldDef, OpaqueTypeKey, ScalarInt, Ty, TyCtxt, TypeVisitableExt, VariantDef, +}; use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; @@ -701,9 +702,9 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ty::Int(_) => miint.as_finite_int(size.bits()).unwrap(), _ => miint.as_finite_uint().unwrap(), }; - match Scalar::try_from_uint(bits, size) { + match ScalarInt::try_from_uint(bits, size) { Some(scalar) => { - let value = mir::Const::from_scalar(tcx, scalar, ty.inner()); + let value = mir::Const::from_scalar(tcx, scalar.into(), ty.inner()); PatRangeBoundary::Finite(value) } // The value doesn't fit. Since `x >= 0` and 0 always encodes the minimum value @@ -737,7 +738,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { // this). We show this to the user as `usize::MAX..` which is slightly incorrect but // probably clear enough. let c = ty.numeric_max_val(cx.tcx).unwrap(); - let value = mir::Const::from_ty_const(c, cx.tcx); + let value = mir::Const::from_ty_const(c, ty.0, cx.tcx); lo = PatRangeBoundary::Finite(value); } let hi = if let Some(hi) = range.hi.minus_one() { diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index c57f22a0da2..2bb1be22b98 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" # tidy-alphabetical-start field-offset = "0.3.5" measureme = "11" -rustc-rayon-core = { version = "0.5.0", optional = true } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hir = { path = "../rustc_hir" } @@ -23,5 +22,5 @@ tracing = "0.1" [features] # tidy-alphabetical-start -rustc_use_parallel_compiler = ["rustc-rayon-core", "rustc_query_system/rustc_use_parallel_compiler"] +rustc_use_parallel_compiler = ["rustc_query_system/rustc_use_parallel_compiler"] # tidy-alphabetical-end diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 76227a78c3d..66fb3136805 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -64,7 +64,6 @@ pub struct MarkFrame<'a> { parent: Option<&'a MarkFrame<'a>>, } -#[derive(PartialEq)] enum DepNodeColor { Red, Green(DepNodeIndex), @@ -925,7 +924,7 @@ impl<D: Deps> DepGraph<D> { /// Returns true if the given node has been marked as red during the /// current compilation session. Used in various assertions pub fn is_red(&self, dep_node: &DepNode) -> bool { - self.node_color(dep_node) == Some(DepNodeColor::Red) + matches!(self.node_color(dep_node), Some(DepNodeColor::Red)) } /// Returns true if the given node has been marked as green during the diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index f824e4faf5d..358f25e2334 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -11,6 +11,10 @@ resolve_added_macro_use = resolve_ancestor_only = visibilities can only be restricted to ancestor modules +resolve_anonymous_livetime_non_gat_report_error = + in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + .label = this lifetime must come from the implemented type + resolve_arguments_macro_use_not_allowed = arguments to `macro_use` are not allowed here resolve_associated_const_with_similar_name_exists = @@ -234,6 +238,10 @@ resolve_items_in_traits_are_not_importable = resolve_label_with_similar_name_reachable = a label with a similar name is reachable +resolve_lending_iterator_report_error = + associated type `Iterator::Item` is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + .note = you can't create an `Iterator` that borrows each `Item` from itself, but you can instead create a new type that borrows your existing type and implement `Iterator` for that new type. + resolve_lifetime_param_in_enum_discriminant = lifetime parameters may not be used in enum discriminant values diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index cad10571afe..ca97d10617b 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -2,6 +2,7 @@ use crate::{ImplTraitContext, Resolver}; use rustc_ast::visit::FnKind; use rustc_ast::*; use rustc_expand::expand::AstFragment; +use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::LocalDefId; use rustc_span::hygiene::LocalExpnId; @@ -128,7 +129,11 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { ItemKind::Union(..) => DefKind::Union, ItemKind::ExternCrate(..) => DefKind::ExternCrate, ItemKind::TyAlias(..) => DefKind::TyAlias, - ItemKind::Static(s) => DefKind::Static { mutability: s.mutability, nested: false }, + ItemKind::Static(s) => DefKind::Static { + safety: hir::Safety::Safe, + mutability: s.mutability, + nested: false, + }, ItemKind::Const(..) => DefKind::Const, ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn, ItemKind::MacroDef(..) => { @@ -211,8 +216,18 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { let def_kind = match fi.kind { - ForeignItemKind::Static(box StaticForeignItem { ty: _, mutability, expr: _ }) => { - DefKind::Static { mutability, nested: false } + ForeignItemKind::Static(box StaticForeignItem { + ty: _, + mutability, + expr: _, + safety, + }) => { + let safety = match safety { + ast::Safety::Unsafe(_) | ast::Safety::Default => hir::Safety::Unsafe, + ast::Safety::Safe(_) => hir::Safety::Safe, + }; + + DefKind::Static { safety, mutability, nested: false } } ForeignItemKind::Fn(_) => DefKind::Fn, ForeignItemKind::TyAlias(_) => DefKind::ForeignTy, @@ -325,6 +340,16 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { ExprKind::Gen(_, _, _) => { self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span) } + ExprKind::ConstBlock(ref constant) => { + let def = self.create_def( + constant.id, + kw::Empty, + DefKind::InlineConst, + constant.value.span, + ); + self.with_parent(def, |this| visit::walk_anon_const(this, constant)); + return; + } _ => self.parent_def, }; diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 856cfbc01e8..d1541527cf5 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1562,6 +1562,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Some(suggestion) if suggestion.candidate == kw::Underscore => return false, Some(suggestion) => suggestion, }; + + let mut did_label_def_span = false; + if let Some(def_span) = suggestion.res.opt_def_id().map(|def_id| self.def_span(def_id)) { if span.overlaps(def_span) { // Don't suggest typo suggestion for itself like in the following: @@ -1595,31 +1598,38 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { errors::DefinedHere::SingleItem { span, candidate_descr, candidate } } }; + did_label_def_span = true; err.subdiagnostic(self.tcx.dcx(), label); } - let (span, sugg, post) = if let SuggestionTarget::SimilarlyNamed = suggestion.target + let (span, msg, sugg) = if let SuggestionTarget::SimilarlyNamed = suggestion.target && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) && let Some(span) = suggestion.span && let Some(candidate) = suggestion.candidate.as_str().strip_prefix('_') && snippet == candidate { + let candidate = suggestion.candidate; // When the suggested binding change would be from `x` to `_x`, suggest changing the // original binding definition instead. (#60164) - let post = format!(", consider renaming `{}` into `{snippet}`", suggestion.candidate); - (span, snippet, post) - } else { - (span, suggestion.candidate.to_ident_string(), String::new()) - }; - let msg = match suggestion.target { - SuggestionTarget::SimilarlyNamed => format!( - "{} {} with a similar name exists{post}", - suggestion.res.article(), - suggestion.res.descr() - ), - SuggestionTarget::SingleItem => { - format!("maybe you meant this {}", suggestion.res.descr()) + let msg = format!( + "the leading underscore in `{candidate}` marks it as unused, consider renaming it to `{snippet}`" + ); + if !did_label_def_span { + err.span_label(span, format!("`{candidate}` defined here")); } + (span, msg, snippet) + } else { + let msg = match suggestion.target { + SuggestionTarget::SimilarlyNamed => format!( + "{} {} with a similar name exists", + suggestion.res.article(), + suggestion.res.descr() + ), + SuggestionTarget::SingleItem => { + format!("maybe you meant this {}", suggestion.res.descr()) + } + }; + (span, msg, suggestion.candidate.to_ident_string()) }; err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect); true diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index edfeacec7e3..0620f3d709e 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -882,6 +882,23 @@ pub(crate) struct ElidedAnonymousLivetimeReportError { pub(crate) suggestion: Option<ElidedAnonymousLivetimeReportErrorSuggestion>, } +#[derive(Diagnostic)] +#[diag(resolve_lending_iterator_report_error)] +pub(crate) struct LendingIteratorReportError { + #[primary_span] + pub(crate) lifetime: Span, + #[note] + pub(crate) ty: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_anonymous_livetime_non_gat_report_error)] +pub(crate) struct AnonymousLivetimeNonGatReportError { + #[primary_span] + #[label] + pub(crate) lifetime: Span, +} + #[derive(Subdiagnostic)] #[multipart_suggestion( resolve_elided_anonymous_lifetime_report_error_suggestion, diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 57db765c07e..b6a23317dc9 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -965,6 +965,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // if it can then our result is not determined and can be invalidated. for single_import in &resolution.single_imports { let Some(import_vis) = single_import.vis.get() else { + // This branch handles a cycle in single imports, which occurs + // when we've previously captured the `vis` value during an import + // process. + // + // For example: + // ``` + // use a::b; + // use b as a; + // ``` + // 1. Steal the `vis` in `use a::b` and attempt to locate `a` in the + // current module. + // 2. Encounter the import `use b as a`, which is a `single_import` for `a`, + // and try to find `b` in the current module. + // 3. Re-encounter the `use a::b` import since it's a `single_import` of `b`. + // This leads to entering this branch. continue; }; if !self.is_accessible_from(import_vis, parent_scope.module) { @@ -979,15 +994,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // named imports. continue; } + let Some(module) = single_import.imported_module.get() else { return Err((Undetermined, Weak::No)); }; - let ImportKind::Single { source: ident, .. } = single_import.kind else { + let ImportKind::Single { source: ident, target, target_bindings, .. } = + &single_import.kind + else { unreachable!(); }; + if (ident != target) && target_bindings.iter().all(|binding| binding.get().is_none()) { + // This branch allows the binding to be defined or updated later if the target name + // can hide the source but these bindings are not obtained. + // avoiding module inconsistency between the resolve process and the finalize process. + // See more details in #124840 + return Err((Undetermined, Weak::No)); + } match self.resolve_ident_in_module( module, - ident, + *ident, ns, &single_import.parent_scope, None, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 6bbde26db34..6c7afb305ba 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -259,13 +259,18 @@ struct UnresolvedImportError { // Reexports of the form `pub use foo as bar;` where `foo` is `extern crate foo;` // are permitted for backward-compatibility under a deprecation lint. -fn pub_use_of_private_extern_crate_hack(import: Import<'_>, binding: NameBinding<'_>) -> bool { +fn pub_use_of_private_extern_crate_hack( + import: Import<'_>, + binding: NameBinding<'_>, +) -> Option<NodeId> { match (&import.kind, &binding.kind) { - (ImportKind::Single { .. }, NameBindingKind::Import { import: binding_import, .. }) => { - matches!(binding_import.kind, ImportKind::ExternCrate { .. }) - && import.expect_vis().is_public() + (ImportKind::Single { .. }, NameBindingKind::Import { import: binding_import, .. }) + if let ImportKind::ExternCrate { id, .. } = binding_import.kind + && import.expect_vis().is_public() => + { + Some(id) } - _ => false, + _ => None, } } @@ -275,7 +280,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { pub(crate) fn import(&self, binding: NameBinding<'a>, import: Import<'a>) -> NameBinding<'a> { let import_vis = import.expect_vis().to_def_id(); let vis = if binding.vis.is_at_least(import_vis, self.tcx) - || pub_use_of_private_extern_crate_hack(import, binding) + || pub_use_of_private_extern_crate_hack(import, binding).is_some() { import_vis } else { @@ -352,9 +357,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { (old_glob @ true, false) | (old_glob @ false, true) => { let (glob_binding, nonglob_binding) = if old_glob { (old_binding, binding) } else { (binding, old_binding) }; - if glob_binding.res() != nonglob_binding.res() - && key.ns == MacroNS + if key.ns == MacroNS && nonglob_binding.expansion != LocalExpnId::ROOT + && glob_binding.res() != nonglob_binding.res() { resolution.binding = Some(this.ambiguity( AmbiguityKind::GlobVsExpanded, @@ -1253,12 +1258,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // All namespaces must be re-exported with extra visibility for an error to occur. if !any_successful_reexport { let (ns, binding) = reexport_error.unwrap(); - if pub_use_of_private_extern_crate_hack(import, binding) { + if let Some(extern_crate_id) = pub_use_of_private_extern_crate_hack(import, binding) { self.lint_buffer.buffer_lint( PUB_USE_OF_PRIVATE_EXTERN_CRATE, import_id, import.span, - BuiltinLintDiag::PrivateExternCrateReexport(ident), + BuiltinLintDiag::PrivateExternCrateReexport { + source: ident, + extern_crate_span: self.tcx.source_span(self.local_def_id(extern_crate_id)), + }, ); } else { if ns == TypeNS { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index bcf2c9a9206..b0adc3775f6 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -9,7 +9,7 @@ use crate::{errors, path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding}; use crate::{BindingKey, Used}; use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult}; -use crate::{ResolutionError, Resolver, Segment, UseError}; +use crate::{ResolutionError, Resolver, Segment, TyCtxt, UseError}; use rustc_ast::ptr::P; use rustc_ast::visit::{visit_opt, walk_list, AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor}; @@ -629,6 +629,9 @@ struct DiagMetadata<'ast> { in_assignment: Option<&'ast Expr>, is_assign_rhs: bool, + /// If we are setting an associated type in trait impl, is it a non-GAT type? + in_non_gat_assoc_type: Option<bool>, + /// Used to detect possible `.` -> `..` typo when calling methods. in_range: Option<(&'ast Expr, &'ast Expr)>, @@ -1703,10 +1706,35 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { break; } } - self.r.dcx().emit_err(errors::ElidedAnonymousLivetimeReportError { - span: lifetime.ident.span, - suggestion, - }); + + // are we trying to use an anonymous lifetime + // on a non GAT associated trait type? + if !self.in_func_body + && let Some((module, _)) = &self.current_trait_ref + && let Some(ty) = &self.diag_metadata.current_self_type + && Some(true) == self.diag_metadata.in_non_gat_assoc_type + && let crate::ModuleKind::Def(DefKind::Trait, trait_id, _) = module.kind + { + if def_id_matches_path( + self.r.tcx, + trait_id, + &["core", "iter", "traits", "iterator", "Iterator"], + ) { + self.r.dcx().emit_err(errors::LendingIteratorReportError { + lifetime: lifetime.ident.span, + ty: ty.span(), + }); + } else { + self.r.dcx().emit_err(errors::AnonymousLivetimeNonGatReportError { + lifetime: lifetime.ident.span, + }); + } + } else { + self.r.dcx().emit_err(errors::ElidedAnonymousLivetimeReportError { + span: lifetime.ident.span, + suggestion, + }); + } } else { self.r.dcx().emit_err(errors::ExplicitAnonymousLivetimeReportError { span: lifetime.ident.span, @@ -3058,6 +3086,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { ); } AssocItemKind::Type(box TyAlias { generics, .. }) => { + self.diag_metadata.in_non_gat_assoc_type = Some(generics.params.is_empty()); debug!("resolve_implementation AssocItemKind::Type"); // We also need a new scope for the impl item type parameters. self.with_generic_param_rib( @@ -3086,6 +3115,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { }); }, ); + self.diag_metadata.in_non_gat_assoc_type = None; } AssocItemKind::Delegation(box delegation) => { debug!("resolve_implementation AssocItemKind::Delegation"); @@ -4505,10 +4535,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { self.visit_expr(elem); self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::Yes)); } - ExprKind::ConstBlock(ref expr) => { - self.resolve_anon_const_manual(false, AnonConstKind::InlineConst, |this| { - this.visit_expr(expr) - }); + ExprKind::ConstBlock(ref ct) => { + self.resolve_anon_const(ct, AnonConstKind::InlineConst); } ExprKind::Index(ref elem, ref idx, _) => { self.resolve_expr(elem, Some(expr)); @@ -4829,3 +4857,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } } + +/// Check if definition matches a path +fn def_id_matches_path(tcx: TyCtxt<'_>, mut def_id: DefId, expected_path: &[&str]) -> bool { + let mut path = expected_path.iter().rev(); + while let (Some(parent), Some(next_step)) = (tcx.opt_parent(def_id), path.next()) { + if !tcx.opt_item_name(def_id).map_or(false, |n| n.as_str() == *next_step) { + return false; + } + def_id = parent; + } + return true; +} diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index ec24eac4a9d..9eeb0da7ed2 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2041,8 +2041,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn { called }, ast::AssocItemKind::Type(..) => AssocSuggestion::AssocType, ast::AssocItemKind::Delegation(..) - if self.r.delegation_fn_sigs[&self.r.local_def_id(assoc_item.id)] - .has_self => + if self + .r + .delegation_fn_sigs + .get(&self.r.local_def_id(assoc_item.id)) + .map_or(false, |sig| sig.has_self) => { AssocSuggestion::MethodWithSelf { called } } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index d67132d2dd4..0be8b5d5718 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -68,6 +68,8 @@ fn compress<'tcx>( fn encode_args<'tcx>( tcx: TyCtxt<'tcx>, args: GenericArgsRef<'tcx>, + for_def: DefId, + has_erased_self: bool, dict: &mut FxHashMap<DictKey<'tcx>, usize>, options: EncodeTyOptions, ) -> String { @@ -76,7 +78,8 @@ fn encode_args<'tcx>( let args: Vec<GenericArg<'_>> = args.iter().collect(); if !args.is_empty() { s.push('I'); - for arg in args { + let def_generics = tcx.generics_of(for_def); + for (n, arg) in args.iter().enumerate() { match arg.unpack() { GenericArgKind::Lifetime(region) => { s.push_str(&encode_region(region, dict)); @@ -85,7 +88,10 @@ fn encode_args<'tcx>( s.push_str(&encode_ty(tcx, ty, dict, options)); } GenericArgKind::Const(c) => { - s.push_str(&encode_const(tcx, c, dict, options)); + let n = n + (has_erased_self as usize); + let ct_ty = + tcx.type_of(def_generics.param_at(n, tcx).def_id).instantiate_identity(); + s.push_str(&encode_const(tcx, c, ct_ty, dict, options)); } } } @@ -99,6 +105,7 @@ fn encode_args<'tcx>( fn encode_const<'tcx>( tcx: TyCtxt<'tcx>, c: Const<'tcx>, + ct_ty: Ty<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, usize>, options: EncodeTyOptions, ) -> String { @@ -111,20 +118,20 @@ fn encode_const<'tcx>( // L<element-type>E as literal argument // Element type - s.push_str(&encode_ty(tcx, c.ty(), dict, options)); + s.push_str(&encode_ty(tcx, ct_ty, dict, options)); } // Literal arguments - ty::ConstKind::Value(..) => { + ty::ConstKind::Value(ct_ty, ..) => { // L<element-type>[n]<element-value>E as literal argument // Element type - s.push_str(&encode_ty(tcx, c.ty(), dict, options)); + s.push_str(&encode_ty(tcx, ct_ty, dict, options)); // The only allowed types of const values are bool, u8, u16, u32, // u64, u128, usize i8, i16, i32, i64, i128, isize, and char. The // bool value false is encoded as 0 and true as 1. - match c.ty().kind() { + match ct_ty.kind() { ty::Int(ity) => { let bits = c.eval_bits(tcx, ty::ParamEnv::reveal_all()); let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128; @@ -142,7 +149,7 @@ fn encode_const<'tcx>( let _ = write!(s, "{val}"); } _ => { - bug!("encode_const: unexpected type `{:?}`", c.ty()); + bug!("encode_const: unexpected type `{:?}`", ct_ty); } } } @@ -231,15 +238,21 @@ fn encode_predicate<'tcx>( ty::ExistentialPredicate::Trait(trait_ref) => { let name = encode_ty_name(tcx, trait_ref.def_id); let _ = write!(s, "u{}{}", name.len(), &name); - s.push_str(&encode_args(tcx, trait_ref.args, dict, options)); + s.push_str(&encode_args(tcx, trait_ref.args, trait_ref.def_id, true, dict, options)); } ty::ExistentialPredicate::Projection(projection) => { let name = encode_ty_name(tcx, projection.def_id); let _ = write!(s, "u{}{}", name.len(), &name); - s.push_str(&encode_args(tcx, projection.args, dict, options)); + s.push_str(&encode_args(tcx, projection.args, projection.def_id, true, dict, options)); match projection.term.unpack() { TermKind::Ty(ty) => s.push_str(&encode_ty(tcx, ty, dict, options)), - TermKind::Const(c) => s.push_str(&encode_const(tcx, c, dict, options)), + TermKind::Const(c) => s.push_str(&encode_const( + tcx, + c, + tcx.type_of(projection.def_id).instantiate(tcx, projection.args), + dict, + options, + )), } } ty::ExistentialPredicate::AutoTrait(def_id) => { @@ -485,7 +498,7 @@ pub fn encode_ty<'tcx>( // <subst>, as vendor extended type. let name = encode_ty_name(tcx, def_id); let _ = write!(s, "u{}{}", name.len(), &name); - s.push_str(&encode_args(tcx, args, dict, options)); + s.push_str(&encode_args(tcx, args, def_id, false, dict, options)); compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); } typeid.push_str(&s); @@ -529,7 +542,7 @@ pub fn encode_ty<'tcx>( let mut s = String::new(); let name = encode_ty_name(tcx, *def_id); let _ = write!(s, "u{}{}", name.len(), &name); - s.push_str(&encode_args(tcx, args, dict, options)); + s.push_str(&encode_args(tcx, args, *def_id, false, dict, options)); compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); typeid.push_str(&s); } @@ -541,7 +554,7 @@ pub fn encode_ty<'tcx>( let name = encode_ty_name(tcx, *def_id); let _ = write!(s, "u{}{}", name.len(), &name); let parent_args = tcx.mk_args(args.as_coroutine_closure().parent_args()); - s.push_str(&encode_args(tcx, parent_args, dict, options)); + s.push_str(&encode_args(tcx, parent_args, *def_id, false, dict, options)); compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); typeid.push_str(&s); } @@ -556,6 +569,8 @@ pub fn encode_ty<'tcx>( s.push_str(&encode_args( tcx, tcx.mk_args(args.as_coroutine().parent_args()), + *def_id, + false, dict, options, )); diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 62eb07e8287..2fbfb93150e 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 @@ -367,7 +367,7 @@ pub fn transform_instance<'tcx>( let trait_method = tcx.associated_item(method_id); let trait_id = trait_ref.skip_binder().def_id; if traits::is_vtable_safe_method(tcx, trait_id, trait_method) - && tcx.object_safety_violations(trait_id).is_empty() + && tcx.is_object_safe(trait_id) { // Trait methods will have a Self polymorphic parameter, where the concreteized // implementatation will not. We need to walk back to the more general trait method diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 9cb8cd836e6..6f63776bedc 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -12,7 +12,7 @@ use tracing::debug; pub struct FileSearch<'a> { sysroot: &'a Path, triple: &'a str, - search_paths: &'a [SearchPath], + cli_search_paths: &'a [SearchPath], tlib_path: &'a SearchPath, kind: PathKind, } @@ -20,7 +20,7 @@ pub struct FileSearch<'a> { impl<'a> FileSearch<'a> { pub fn search_paths(&self) -> impl Iterator<Item = &'a SearchPath> { let kind = self.kind; - self.search_paths + self.cli_search_paths .iter() .filter(move |sp| sp.kind.matches(kind)) .chain(std::iter::once(self.tlib_path)) @@ -37,26 +37,26 @@ impl<'a> FileSearch<'a> { pub fn new( sysroot: &'a Path, triple: &'a str, - search_paths: &'a [SearchPath], + cli_search_paths: &'a [SearchPath], tlib_path: &'a SearchPath, kind: PathKind, ) -> FileSearch<'a> { debug!("using sysroot = {}, triple = {}", sysroot.display(), triple); - FileSearch { sysroot, triple, search_paths, tlib_path, kind } + FileSearch { sysroot, triple, cli_search_paths, tlib_path, kind } } } pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf { - let rustlib_path = rustc_target::target_rustlib_path(sysroot, target_triple); - PathBuf::from_iter([sysroot, Path::new(&rustlib_path), Path::new("lib")]) + let rustlib_path = rustc_target::relative_target_rustlib_path(sysroot, target_triple); + sysroot.join(rustlib_path).join("lib") } /// Returns a path to the target's `bin` folder within its `rustlib` path in the sysroot. This is /// where binaries are usually installed, e.g. the self-contained linkers, lld-wrappers, LLVM tools, /// etc. pub fn make_target_bin_path(sysroot: &Path, target_triple: &str) -> PathBuf { - let rustlib_path = rustc_target::target_rustlib_path(sysroot, target_triple); - PathBuf::from_iter([sysroot, Path::new(&rustlib_path), Path::new("bin")]) + let rustlib_path = rustc_target::relative_target_rustlib_path(sysroot, target_triple); + sysroot.join(rustlib_path).join("bin") } #[cfg(unix)] @@ -275,7 +275,7 @@ pub fn get_or_default_sysroot() -> Result<PathBuf, String> { p.pop(); p.pop(); // Look for the target rustlib directory in the suspected sysroot. - let mut rustlib_path = rustc_target::target_rustlib_path(&p, "dummy"); + let mut rustlib_path = rustc_target::relative_target_rustlib_path(&p, "dummy"); rustlib_path.pop(); // pop off the dummy target. rustlib_path.exists().then_some(p) } diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 6ec710f97d1..c33a52f4a7a 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -5,17 +5,17 @@ // Prefer importing stable_mir over internal rustc constructs to make this file more readable. use crate::rustc_smir::Tables; -use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy, TyCtxt}; +use rustc_middle::ty::{self as rustc_ty, Const as InternalConst, Ty as InternalTy, TyCtxt}; use rustc_span::Symbol; use stable_mir::abi::Layout; use stable_mir::mir::alloc::AllocId; use stable_mir::mir::mono::{Instance, MonoItem, StaticDef}; use stable_mir::mir::{BinOp, Mutability, Place, ProjectionElem, Safety, UnOp}; use stable_mir::ty::{ - Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, - DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig, - GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Pattern, Region, RigidTy, Span, - TermKind, TraitRef, Ty, UintTy, VariantDef, VariantIdx, + Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, DynKind, + ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig, + GenericArgKind, GenericArgs, IndexedVal, IntTy, MirConst, Movability, Pattern, Region, RigidTy, + Span, TermKind, TraitRef, Ty, TyConst, UintTy, VariantDef, VariantIdx, }; use stable_mir::{CrateItem, CrateNum, DefId}; @@ -55,7 +55,7 @@ impl RustcInternal for GenericArgKind { let arg: rustc_ty::GenericArg<'tcx> = match self { GenericArgKind::Lifetime(reg) => reg.internal(tables, tcx).into(), GenericArgKind::Type(ty) => ty.internal(tables, tcx).into(), - GenericArgKind::Const(cnst) => ty_const(cnst, tables, tcx).into(), + GenericArgKind::Const(cnst) => cnst.internal(tables, tcx).into(), }; tcx.lift(arg).unwrap() } @@ -76,13 +76,20 @@ impl RustcInternal for Ty { } } +impl RustcInternal for TyConst { + type T<'tcx> = InternalConst<'tcx>; + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + tcx.lift(tables.ty_consts[self.id]).unwrap() + } +} + impl RustcInternal for Pattern { type T<'tcx> = rustc_ty::Pattern<'tcx>; fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { tcx.mk_pat(match self { Pattern::Range { start, end, include_end } => rustc_ty::PatternKind::Range { - start: start.as_ref().map(|c| ty_const(c, tables, tcx)), - end: end.as_ref().map(|c| ty_const(c, tables, tcx)), + start: start.as_ref().map(|c| c.internal(tables, tcx)), + end: end.as_ref().map(|c| c.internal(tables, tcx)), include_end: *include_end, }, }) @@ -101,7 +108,7 @@ impl RustcInternal for RigidTy { RigidTy::Float(float_ty) => rustc_ty::TyKind::Float(float_ty.internal(tables, tcx)), RigidTy::Never => rustc_ty::TyKind::Never, RigidTy::Array(ty, cnst) => { - rustc_ty::TyKind::Array(ty.internal(tables, tcx), ty_const(cnst, tables, tcx)) + rustc_ty::TyKind::Array(ty.internal(tables, tcx), cnst.internal(tables, tcx)) } RigidTy::Pat(ty, pat) => { rustc_ty::TyKind::Pat(ty.internal(tables, tcx), pat.internal(tables, tcx)) @@ -239,25 +246,14 @@ impl RustcInternal for VariantDef { } } -fn ty_const<'tcx>( - constant: &Const, - tables: &mut Tables<'_>, - tcx: TyCtxt<'tcx>, -) -> rustc_ty::Const<'tcx> { - match constant.internal(tables, tcx) { - rustc_middle::mir::Const::Ty(c) => c, - cnst => { - panic!("Trying to convert constant `{constant:?}` to type constant, but found {cnst:?}") - } - } -} - -impl RustcInternal for Const { +impl RustcInternal for MirConst { type T<'tcx> = rustc_middle::mir::Const<'tcx>; fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { - let constant = tables.constants[self.id]; + let constant = tables.mir_consts[self.id]; match constant { - rustc_middle::mir::Const::Ty(ty) => rustc_middle::mir::Const::Ty(tcx.lift(ty).unwrap()), + rustc_middle::mir::Const::Ty(ty, ct) => { + rustc_middle::mir::Const::Ty(tcx.lift(ty).unwrap(), tcx.lift(ct).unwrap()) + } rustc_middle::mir::Const::Unevaluated(uneval, ty) => { rustc_middle::mir::Const::Unevaluated( tcx.lift(uneval).unwrap(), @@ -392,7 +388,7 @@ impl RustcInternal for TermKind { fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { match self { TermKind::Type(ty) => ty.internal(tables, tcx).into(), - TermKind::Const(const_) => ty_const(const_, tables, tcx).into(), + TermKind::Const(cnst) => cnst.internal(tables, tcx).into(), } } } diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index 6e870728baf..810ffc142a0 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -214,7 +214,8 @@ where spans: IndexMap::default(), types: IndexMap::default(), instances: IndexMap::default(), - constants: IndexMap::default(), + ty_consts: IndexMap::default(), + mir_consts: IndexMap::default(), layouts: IndexMap::default(), })); stable_mir::compiler_interface::run(&tables, || init(&tables, f)) diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index fa7b2a30ba6..a8688c88601 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -6,7 +6,6 @@ #![allow(rustc::usage_of_qualified_ty)] use rustc_abi::HasDataLayout; -use rustc_middle::ty; use rustc_middle::ty::layout::{ FnAbiOf, FnAbiOfHelpers, HasParamEnv, HasTyCtxt, LayoutOf, LayoutOfHelpers, }; @@ -14,6 +13,7 @@ use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths}; use rustc_middle::ty::{ GenericPredicates, Instance, List, ParamEnv, ScalarInt, TyCtxt, TypeVisitableExt, ValTree, }; +use rustc_middle::{mir, ty}; use rustc_span::def_id::LOCAL_CRATE; use stable_mir::abi::{FnAbi, Layout, LayoutShape}; use stable_mir::compiler_interface::Context; @@ -22,9 +22,9 @@ use stable_mir::mir::mono::{InstanceDef, StaticDef}; use stable_mir::mir::{BinOp, Body, Place, UnOp}; use stable_mir::target::{MachineInfo, MachineSize}; use stable_mir::ty::{ - AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef, - ForeignItemKind, GenericArgs, IntrinsicDef, LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind, - UintTy, VariantDef, + AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, FieldDef, FnDef, ForeignDef, + ForeignItemKind, GenericArgs, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span, Ty, + TyConst, TyKind, UintTy, VariantDef, }; use stable_mir::{Crate, CrateDef, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol}; use std::cell::RefCell; @@ -126,7 +126,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; iter::once(LOCAL_CRATE) - .chain(tables.tcx.used_crates(()).iter().copied()) + .chain(tables.tcx.crates(()).iter().copied()) .flat_map(|cnum| tcx.trait_impls_in_crate(cnum).iter()) .map(|impl_def_id| tables.impl_def(*impl_def_id)) .collect() @@ -201,19 +201,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn external_crates(&self) -> Vec<stable_mir::Crate> { let tables = self.0.borrow(); - tables - .tcx - .used_crates(()) - .iter() - .map(|crate_num| smir_crate(tables.tcx, *crate_num)) - .collect() + tables.tcx.crates(()).iter().map(|crate_num| smir_crate(tables.tcx, *crate_num)).collect() } fn find_crates(&self, name: &str) -> Vec<stable_mir::Crate> { let tables = self.0.borrow(); let crates: Vec<stable_mir::Crate> = [LOCAL_CRATE] .iter() - .chain(tables.tcx.used_crates(()).iter()) + .chain(tables.tcx.crates(()).iter()) .filter_map(|crate_num| { let crate_name = tables.tcx.crate_name(*crate_num).to_string(); (name == crate_name).then(|| smir_crate(tables.tcx, *crate_num)) @@ -360,7 +355,15 @@ impl<'tcx> Context for TablesWrapper<'tcx> { def.internal(&mut *tables, tcx).fields.iter().map(|f| f.stable(&mut *tables)).collect() } - fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error> { + fn eval_target_usize(&self, cnst: &MirConst) -> Result<u64, Error> { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let mir_const = cnst.internal(&mut *tables, tcx); + mir_const + .try_eval_target_usize(tables.tcx, ParamEnv::empty()) + .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64"))) + } + fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result<u64, Error> { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let mir_const = cnst.internal(&mut *tables, tcx); @@ -369,7 +372,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .ok_or_else(|| Error::new(format!("Const `{cnst:?}` cannot be encoded as u64"))) } - fn try_new_const_zst(&self, ty: Ty) -> Result<Const, Error> { + fn try_new_const_zst(&self, ty: Ty) -> Result<MirConst, Error> { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let ty_internal = ty.internal(&mut *tables, tcx); @@ -390,25 +393,46 @@ impl<'tcx> Context for TablesWrapper<'tcx> { ))); } - Ok(ty::Const::zero_sized(tables.tcx, ty_internal).stable(&mut *tables)) + Ok(mir::Const::Ty(ty_internal, ty::Const::zero_sized(tables.tcx, ty_internal)) + .stable(&mut *tables)) } - fn new_const_str(&self, value: &str) -> Const { + fn new_const_str(&self, value: &str) -> MirConst { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let ty = ty::Ty::new_static_str(tcx); let bytes = value.as_bytes(); let val_tree = ty::ValTree::from_raw_bytes(tcx, bytes); - ty::Const::new_value(tcx, val_tree, ty).stable(&mut *tables) + let ct = ty::Const::new_value(tcx, val_tree, ty); + super::convert::mir_const_from_ty_const(&mut *tables, ct, ty) } - fn new_const_bool(&self, value: bool) -> Const { + fn new_const_bool(&self, value: bool) -> MirConst { let mut tables = self.0.borrow_mut(); - ty::Const::from_bool(tables.tcx, value).stable(&mut *tables) + let ct = ty::Const::from_bool(tables.tcx, value); + let ty = tables.tcx.types.bool; + super::convert::mir_const_from_ty_const(&mut *tables, ct, ty) } - fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<Const, Error> { + fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<MirConst, Error> { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let ty = ty::Ty::new_uint(tcx, uint_ty.internal(&mut *tables, tcx)); + let size = tables.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap().size; + + // We don't use Const::from_bits since it doesn't have any error checking. + let scalar = ScalarInt::try_from_uint(value, size).ok_or_else(|| { + Error::new(format!("Value overflow: cannot convert `{value}` to `{ty}`.")) + })?; + let ct = ty::Const::new_value(tables.tcx, ValTree::from_scalar_int(scalar), ty); + Ok(super::convert::mir_const_from_ty_const(&mut *tables, ct, ty)) + } + fn try_new_ty_const_uint( + &self, + value: u128, + uint_ty: UintTy, + ) -> Result<stable_mir::ty::TyConst, Error> { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let ty = ty::Ty::new_uint(tcx, uint_ty.internal(&mut *tables, tcx)); @@ -453,7 +477,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { .stable(&mut *tables) } - fn const_pretty(&self, cnst: &stable_mir::ty::Const) -> String { + fn mir_const_pretty(&self, cnst: &stable_mir::ty::MirConst) -> String { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; cnst.internal(&mut *tables, tcx).to_string() @@ -474,6 +498,11 @@ impl<'tcx> Context for TablesWrapper<'tcx> { tables.types[ty].kind().stable(&mut *tables) } + fn ty_const_pretty(&self, ct: stable_mir::ty::TyConstId) -> String { + let tables = self.0.borrow_mut(); + tables.ty_consts[ct].to_string() + } + fn rigid_ty_discriminant_ty(&self, ty: &RigidTy) -> stable_mir::ty::Ty { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index a1a5c09ef0a..bcacf54baf3 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -6,7 +6,7 @@ use rustc_middle::mir::interpret::alloc_range; use rustc_middle::mir::mono::MonoItem; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::{ConstOperand, Statement, UserTypeProjection, VarDebugInfoFragment}; -use stable_mir::ty::{Allocation, Const, ConstantKind}; +use stable_mir::ty::{Allocation, ConstantKind, MirConst}; use stable_mir::{opaque, Error}; use crate::rustc_smir::{alloc, Stable, Tables}; @@ -724,11 +724,16 @@ impl<'tcx> Stable<'tcx> for mir::interpret::GlobalAlloc<'tcx> { } impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> { - type T = stable_mir::ty::Const; + type T = stable_mir::ty::MirConst; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { + let id = tables.intern_mir_const(tables.tcx.lift(*self).unwrap()); match *self { - mir::Const::Ty(c) => c.stable(tables), + mir::Const::Ty(ty, c) => MirConst::new( + stable_mir::ty::ConstantKind::Ty(c.stable(tables)), + ty.stable(tables), + id, + ), mir::Const::Unevaluated(unev_const, ty) => { let kind = stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst { @@ -737,21 +742,18 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> { promoted: unev_const.promoted.map(|u| u.as_u32()), }); let ty = ty.stable(tables); - let id = tables.intern_const(tables.tcx.lift(*self).unwrap()); - Const::new(kind, ty, id) + MirConst::new(kind, ty, id) } mir::Const::Val(mir::ConstValue::ZeroSized, ty) => { let ty = ty.stable(tables); - let id = tables.intern_const(tables.tcx.lift(*self).unwrap()); - Const::new(ConstantKind::ZeroSized, ty, id) + MirConst::new(ConstantKind::ZeroSized, ty, id) } mir::Const::Val(val, ty) => { let ty = tables.tcx.lift(ty).unwrap(); let val = tables.tcx.lift(val).unwrap(); let kind = ConstantKind::Allocated(alloc::new_allocation(ty, val, tables)); let ty = ty.stable(tables); - let id = tables.intern_const(tables.tcx.lift(*self).unwrap()); - Const::new(kind, ty, id) + MirConst::new(kind, ty, id) } } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs index 736378a530f..50687935473 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs @@ -9,6 +9,8 @@ mod error; mod mir; mod ty; +pub use ty::mir_const_from_ty_const; + impl<'tcx> Stable<'tcx> for rustc_hir::Safety { type T = stable_mir::mir::Safety; fn stable(&self, _: &mut Tables<'_>) -> Self::T { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 66708def00f..73bc87dc9ab 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -3,8 +3,7 @@ use rustc_middle::ty::Ty; use rustc_middle::{mir, ty}; use stable_mir::ty::{ - AdtKind, Const, ConstantKind, FloatTy, GenericArgs, GenericParamDef, IntTy, Region, RigidTy, - TyKind, UintTy, + AdtKind, FloatTy, GenericArgs, GenericParamDef, IntTy, Region, RigidTy, TyKind, UintTy, }; use crate::rustc_smir::{alloc, Stable, Tables}; @@ -410,45 +409,85 @@ impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> { } } +pub fn mir_const_from_ty_const<'tcx>( + tables: &mut Tables<'tcx>, + ty_const: ty::Const<'tcx>, + ty: Ty<'tcx>, +) -> stable_mir::ty::MirConst { + let kind = match ty_const.kind() { + ty::Value(ty, val) => { + let val = match val { + ty::ValTree::Leaf(scalar) => ty::ValTree::Leaf(scalar), + ty::ValTree::Branch(branch) => { + ty::ValTree::Branch(tables.tcx.lift(branch).unwrap()) + } + }; + let ty = tables.tcx.lift(ty).unwrap(); + let const_val = tables.tcx.valtree_to_const_val((ty, val)); + if matches!(const_val, mir::ConstValue::ZeroSized) { + stable_mir::ty::ConstantKind::ZeroSized + } else { + stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation( + ty, const_val, tables, + )) + } + } + ty::ParamCt(param) => stable_mir::ty::ConstantKind::Param(param.stable(tables)), + ty::ErrorCt(_) => unreachable!(), + ty::InferCt(_) => unreachable!(), + ty::BoundCt(_, _) => unimplemented!(), + ty::PlaceholderCt(_) => unimplemented!(), + ty::Unevaluated(uv) => { + stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst { + def: tables.const_def(uv.def), + args: uv.args.stable(tables), + promoted: None, + }) + } + ty::ExprCt(_) => unimplemented!(), + }; + let stable_ty = tables.intern_ty(ty); + let id = tables.intern_mir_const(mir::Const::Ty(ty, ty_const)); + stable_mir::ty::MirConst::new(kind, stable_ty, id) +} + impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { - type T = stable_mir::ty::Const; + type T = stable_mir::ty::TyConst; fn stable(&self, tables: &mut Tables<'_>) -> Self::T { let kind = match self.kind() { - ty::Value(val) => { + ty::Value(ty, val) => { let val = match val { ty::ValTree::Leaf(scalar) => ty::ValTree::Leaf(scalar), ty::ValTree::Branch(branch) => { ty::ValTree::Branch(tables.tcx.lift(branch).unwrap()) } }; - let ty = tables.tcx.lift(self.ty()).unwrap(); + + let ty = tables.tcx.lift(ty).unwrap(); let const_val = tables.tcx.valtree_to_const_val((ty, val)); if matches!(const_val, mir::ConstValue::ZeroSized) { - ConstantKind::ZeroSized + stable_mir::ty::TyConstKind::ZSTValue(ty.stable(tables)) } else { - stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation( - ty, const_val, tables, - )) + stable_mir::ty::TyConstKind::Value( + ty.stable(tables), + alloc::new_allocation(ty, const_val, tables), + ) } } - ty::ParamCt(param) => stable_mir::ty::ConstantKind::Param(param.stable(tables)), + ty::ParamCt(param) => stable_mir::ty::TyConstKind::Param(param.stable(tables)), + ty::Unevaluated(uv) => stable_mir::ty::TyConstKind::Unevaluated( + tables.const_def(uv.def), + uv.args.stable(tables), + ), ty::ErrorCt(_) => unreachable!(), ty::InferCt(_) => unreachable!(), ty::BoundCt(_, _) => unimplemented!(), ty::PlaceholderCt(_) => unimplemented!(), - ty::Unevaluated(uv) => { - stable_mir::ty::ConstantKind::Unevaluated(stable_mir::ty::UnevaluatedConst { - def: tables.const_def(uv.def), - args: uv.args.stable(tables), - promoted: None, - }) - } ty::ExprCt(_) => unimplemented!(), }; - let ty = self.ty().stable(tables); - let id = tables.intern_const(mir::Const::Ty(tables.tcx.lift(*self).unwrap())); - Const::new(kind, ty, id) + let id = tables.intern_ty_const(tables.tcx.lift(*self).unwrap()); + stable_mir::ty::TyConst::new(kind, id) } } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index aba7e7dc9c2..d13e7803326 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE}; use stable_mir::abi::Layout; use stable_mir::mir::mono::InstanceDef; -use stable_mir::ty::{ConstId, Span}; +use stable_mir::ty::{MirConstId, Span, TyConstId}; use stable_mir::{CtorKind, ItemKind}; use std::ops::RangeInclusive; use tracing::debug; @@ -33,7 +33,8 @@ pub struct Tables<'tcx> { pub(crate) spans: IndexMap<rustc_span::Span, Span>, pub(crate) types: IndexMap<Ty<'tcx>, stable_mir::ty::Ty>, pub(crate) instances: IndexMap<ty::Instance<'tcx>, InstanceDef>, - pub(crate) constants: IndexMap<mir::Const<'tcx>, ConstId>, + pub(crate) ty_consts: IndexMap<ty::Const<'tcx>, TyConstId>, + pub(crate) mir_consts: IndexMap<mir::Const<'tcx>, MirConstId>, pub(crate) layouts: IndexMap<rustc_target::abi::Layout<'tcx>, Layout>, } @@ -42,8 +43,12 @@ impl<'tcx> Tables<'tcx> { self.types.create_or_fetch(ty) } - pub(crate) fn intern_const(&mut self, constant: mir::Const<'tcx>) -> ConstId { - self.constants.create_or_fetch(constant) + pub(crate) fn intern_ty_const(&mut self, ct: ty::Const<'tcx>) -> TyConstId { + self.ty_consts.create_or_fetch(ct) + } + + pub(crate) fn intern_mir_const(&mut self, constant: mir::Const<'tcx>) -> MirConstId { + self.mir_consts.create_or_fetch(constant) } pub(crate) fn has_body(&self, instance: Instance<'tcx>) -> bool { diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index b2ca01fe3b9..99fcaf917fe 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -521,7 +521,7 @@ impl SpanData { Span::new(self.lo, hi, self.ctxt, self.parent) } #[inline] - pub fn with_ctxt(&self, ctxt: SyntaxContext) -> Span { + fn with_ctxt(&self, ctxt: SyntaxContext) -> Span { Span::new(self.lo, self.hi, ctxt, self.parent) } #[inline] @@ -576,8 +576,9 @@ impl Span { self.data().with_hi(hi) } #[inline] - pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span { - self.data_untracked().with_ctxt(ctxt) + pub fn with_ctxt(mut self, ctxt: SyntaxContext) -> Span { + self.update_ctxt(|_| ctxt); + self } #[inline] pub fn parent(self) -> Option<LocalDefId> { @@ -682,6 +683,13 @@ impl Span { if span.hi > other.hi { Some(span.with_lo(cmp::max(span.lo, other.hi))) } else { None } } + /// Returns `Some(span)`, where the end is trimmed by the start of `other`. + pub fn trim_end(self, other: Span) -> Option<Span> { + let span = self.data(); + let other = other.data(); + if span.lo < other.lo { Some(span.with_hi(cmp::min(span.hi, other.lo))) } else { None } + } + /// Returns the source span -- this is either the supplied span, or the span for /// the macro callsite that expanded to it. pub fn source_callsite(self) -> Span { @@ -1051,9 +1059,9 @@ impl Span { } #[inline] - pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span { - let span = self.data(); - span.with_ctxt(span.ctxt.apply_mark(expn_id, transparency)) + pub fn apply_mark(mut self, expn_id: ExpnId, transparency: Transparency) -> Span { + self.update_ctxt(|ctxt| ctxt.apply_mark(expn_id, transparency)); + self } #[inline] @@ -1101,15 +1109,15 @@ impl Span { } #[inline] - pub fn normalize_to_macros_2_0(self) -> Span { - let span = self.data(); - span.with_ctxt(span.ctxt.normalize_to_macros_2_0()) + pub fn normalize_to_macros_2_0(mut self) -> Span { + self.update_ctxt(|ctxt| ctxt.normalize_to_macros_2_0()); + self } #[inline] - pub fn normalize_to_macro_rules(self) -> Span { - let span = self.data(); - span.with_ctxt(span.ctxt.normalize_to_macro_rules()) + pub fn normalize_to_macro_rules(mut self) -> Span { + self.update_ctxt(|ctxt| ctxt.normalize_to_macro_rules()); + self } } diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 788a52faf56..52a1267f891 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -87,6 +87,45 @@ pub struct Span { ctxt_or_parent_or_marker: u16, } +impl Span { + #[inline] + fn data_inline_ctxt(self) -> SpanData { + let len = self.len_with_tag_or_marker as u32; + debug_assert!(len <= MAX_LEN); + SpanData { + lo: BytePos(self.lo_or_index), + hi: BytePos(self.lo_or_index.debug_strict_add(len)), + ctxt: SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32), + parent: None, + } + } + #[inline] + fn data_inline_parent(self) -> SpanData { + let len = (self.len_with_tag_or_marker & !PARENT_TAG) as u32; + debug_assert!(len <= MAX_LEN); + let parent = LocalDefId { + local_def_index: DefIndex::from_u32(self.ctxt_or_parent_or_marker as u32), + }; + SpanData { + lo: BytePos(self.lo_or_index), + hi: BytePos(self.lo_or_index.debug_strict_add(len)), + ctxt: SyntaxContext::root(), + parent: Some(parent), + } + } + #[inline] + fn data_partially_interned(self) -> SpanData { + SpanData { + ctxt: SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32), + ..with_span_interner(|interner| interner.spans[self.lo_or_index as usize]) + } + } + #[inline] + fn data_interned(self) -> SpanData { + with_span_interner(|interner| interner.spans[self.lo_or_index as usize]) + } +} + // `MAX_LEN` is chosen so that `PARENT_TAG | MAX_LEN` is distinct from // `BASE_LEN_INTERNED_MARKER`. (If `MAX_LEN` was 1 higher, this wouldn't be true.) const MAX_LEN: u32 = 0b0111_1111_1111_1110; @@ -111,42 +150,49 @@ impl Span { std::mem::swap(&mut lo, &mut hi); } - let (lo2, len, ctxt2) = (lo.0, hi.0 - lo.0, ctxt.as_u32()); - + // Small len may enable one of fully inline formats (or may not). + let (len, ctxt32) = (hi.0 - lo.0, ctxt.as_u32()); if len <= MAX_LEN { - if ctxt2 <= MAX_CTXT && parent.is_none() { + if ctxt32 <= MAX_CTXT && parent.is_none() { // Inline-context format. return Span { - lo_or_index: lo2, + lo_or_index: lo.0, len_with_tag_or_marker: len as u16, - ctxt_or_parent_or_marker: ctxt2 as u16, + ctxt_or_parent_or_marker: ctxt32 as u16, }; - } else if ctxt2 == SyntaxContext::root().as_u32() + } else if ctxt32 == 0 && let Some(parent) = parent - && let parent2 = parent.local_def_index.as_u32() - && parent2 <= MAX_CTXT + && let parent32 = parent.local_def_index.as_u32() + && parent32 <= MAX_CTXT { // Inline-parent format. return Span { - lo_or_index: lo2, + lo_or_index: lo.0, len_with_tag_or_marker: PARENT_TAG | len as u16, - ctxt_or_parent_or_marker: parent2 as u16, + ctxt_or_parent_or_marker: parent32 as u16, }; } } - // Partially-interned or fully-interned format. - let index = - with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent })); - let ctxt_or_parent_or_marker = if ctxt2 <= MAX_CTXT { - ctxt2 as u16 // partially-interned - } else { - CTXT_INTERNED_MARKER // fully-interned + // Otherwise small ctxt may enable the partially inline format. + let index = |ctxt| { + with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent })) }; - Span { - lo_or_index: index, - len_with_tag_or_marker: BASE_LEN_INTERNED_MARKER, - ctxt_or_parent_or_marker, + if ctxt32 <= MAX_CTXT { + // Partially-interned format. + Span { + // Interned ctxt should never be read, so it can use any value. + lo_or_index: index(SyntaxContext::from_u32(u32::MAX)), + len_with_tag_or_marker: BASE_LEN_INTERNED_MARKER, + ctxt_or_parent_or_marker: ctxt32 as u16, + } + } else { + // Interned format. + Span { + lo_or_index: index(ctxt), + len_with_tag_or_marker: BASE_LEN_INTERNED_MARKER, + ctxt_or_parent_or_marker: CTXT_INTERNED_MARKER, + } } } @@ -166,34 +212,17 @@ impl Span { if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { if self.len_with_tag_or_marker & PARENT_TAG == 0 { // Inline-context format. - let len = self.len_with_tag_or_marker as u32; - debug_assert!(len <= MAX_LEN); - SpanData { - lo: BytePos(self.lo_or_index), - hi: BytePos(self.lo_or_index.debug_strict_add(len)), - ctxt: SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32), - parent: None, - } + self.data_inline_ctxt() } else { // Inline-parent format. - let len = (self.len_with_tag_or_marker & !PARENT_TAG) as u32; - debug_assert!(len <= MAX_LEN); - let parent = LocalDefId { - local_def_index: DefIndex::from_u32(self.ctxt_or_parent_or_marker as u32), - }; - SpanData { - lo: BytePos(self.lo_or_index), - hi: BytePos(self.lo_or_index.debug_strict_add(len)), - ctxt: SyntaxContext::root(), - parent: Some(parent), - } + self.data_inline_parent() } + } else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { + // Partially-interned format. + self.data_partially_interned() } else { - // Fully-interned or partially-interned format. In either case, - // the interned value contains all the data, so we don't need to - // distinguish them. - let index = self.lo_or_index; - with_span_interner(|interner| interner.spans[index as usize]) + // Interned format. + self.data_interned() } } @@ -214,26 +243,73 @@ impl Span { } } + // For optimization we are interested in cases in which the context is inline and the context + // update doesn't change format. All non-inline or format changing scenarios require accessing + // interner and can fall back to `Span::new`. + #[inline] + pub fn update_ctxt(&mut self, update: impl FnOnce(SyntaxContext) -> SyntaxContext) { + let (updated_ctxt32, data); + if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { + if self.len_with_tag_or_marker & PARENT_TAG == 0 { + // Inline-context format. + updated_ctxt32 = + update(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)).as_u32(); + // Any small new context including zero will preserve the format. + if updated_ctxt32 <= MAX_CTXT { + self.ctxt_or_parent_or_marker = updated_ctxt32 as u16; + return; + } + data = self.data_inline_ctxt(); + } else { + // Inline-parent format. + updated_ctxt32 = update(SyntaxContext::root()).as_u32(); + // Only if the new context is zero the format will be preserved. + if updated_ctxt32 == 0 { + // Do nothing. + return; + } + data = self.data_inline_parent(); + } + } else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { + // Partially-interned format. + updated_ctxt32 = + update(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)).as_u32(); + // Any small new context excluding zero will preserve the format. + // Zero may change the format to `InlineParent` if parent and len are small enough. + if updated_ctxt32 <= MAX_CTXT && updated_ctxt32 != 0 { + self.ctxt_or_parent_or_marker = updated_ctxt32 as u16; + return; + } + data = self.data_partially_interned(); + } else { + // Interned format. + data = self.data_interned(); + updated_ctxt32 = update(data.ctxt).as_u32(); + } + + // We could not keep the span in the same inline format, fall back to the complete logic. + *self = data.with_ctxt(SyntaxContext::from_u32(updated_ctxt32)); + } + // Returns either syntactic context, if it can be retrieved without taking the interner lock, // or an index into the interner if it cannot. + #[inline] fn inline_ctxt(self) -> Result<SyntaxContext, usize> { - Ok(if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { + if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { if self.len_with_tag_or_marker & PARENT_TAG == 0 { // Inline-context format. - SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32) + Ok(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)) } else { - // Inline-parent format. We know that the SyntaxContext is root. - SyntaxContext::root() + // Inline-parent format. + Ok(SyntaxContext::root()) } } else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { - // Partially-interned format. This path avoids looking up the - // interned value, and is the whole point of the - // partially-interned format. - SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32) + // Partially-interned format. + Ok(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)) } else { - // Fully-interned format. - return Err(self.lo_or_index as usize); - }) + // Interned format. + Err(self.lo_or_index as usize) + } } /// This function is used as a fast path when decoding the full `SpanData` is not necessary. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 61ca0d54ca4..e245dfb9f5d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -103,6 +103,7 @@ symbols! { MacroRules: "macro_rules", Raw: "raw", Reuse: "reuse", + Safe: "safe", Union: "union", Yeet: "yeet", } @@ -1303,6 +1304,7 @@ symbols! { offset_of, offset_of_enum, offset_of_nested, + offset_of_slice, ok_or_else, omit_gdb_pretty_printer_section, on, @@ -1961,9 +1963,11 @@ symbols! { unreachable_display, unreachable_macro, unrestricted_attribute_tokens, + unsafe_attributes, unsafe_block_in_unsafe_fn, unsafe_cell, unsafe_cell_raw_get, + unsafe_extern_blocks, unsafe_no_drop_flag, unsafe_pin_internals, unsize, @@ -2213,6 +2217,7 @@ impl fmt::Display for IdentPrinter { pub struct MacroRulesNormalizedIdent(Ident); impl MacroRulesNormalizedIdent { + #[inline] pub fn new(ident: Ident) -> Self { Self(ident.normalize_to_macro_rules()) } diff --git a/compiler/rustc_span/src/tests.rs b/compiler/rustc_span/src/tests.rs index cb88fa89058..48fa786fb1c 100644 --- a/compiler/rustc_span/src/tests.rs +++ b/compiler/rustc_span/src/tests.rs @@ -42,3 +42,60 @@ fn test_normalize_newlines() { check("\r\r\n", "\r\n", &[2]); check("hello\rworld", "hello\rworld", &[]); } + +#[test] +fn test_trim() { + let span = |lo: usize, hi: usize| { + Span::new(BytePos::from_usize(lo), BytePos::from_usize(hi), SyntaxContext::root(), None) + }; + + // Various positions, named for their relation to `start` and `end`. + let well_before = 1; + let before = 3; + let start = 5; + let mid = 7; + let end = 9; + let after = 11; + let well_after = 13; + + // The resulting span's context should be that of `self`, not `other`. + let other = span(start, end).with_ctxt(SyntaxContext::from_u32(999)); + + // Test cases for `trim_end`. + + assert_eq!(span(well_before, before).trim_end(other), Some(span(well_before, before))); + assert_eq!(span(well_before, start).trim_end(other), Some(span(well_before, start))); + assert_eq!(span(well_before, mid).trim_end(other), Some(span(well_before, start))); + assert_eq!(span(well_before, end).trim_end(other), Some(span(well_before, start))); + assert_eq!(span(well_before, after).trim_end(other), Some(span(well_before, start))); + + assert_eq!(span(start, mid).trim_end(other), None); + assert_eq!(span(start, end).trim_end(other), None); + assert_eq!(span(start, after).trim_end(other), None); + + assert_eq!(span(mid, end).trim_end(other), None); + assert_eq!(span(mid, after).trim_end(other), None); + + assert_eq!(span(end, after).trim_end(other), None); + + assert_eq!(span(after, well_after).trim_end(other), None); + + // Test cases for `trim_start`. + + assert_eq!(span(after, well_after).trim_start(other), Some(span(after, well_after))); + assert_eq!(span(end, well_after).trim_start(other), Some(span(end, well_after))); + assert_eq!(span(mid, well_after).trim_start(other), Some(span(end, well_after))); + assert_eq!(span(start, well_after).trim_start(other), Some(span(end, well_after))); + assert_eq!(span(before, well_after).trim_start(other), Some(span(end, well_after))); + + assert_eq!(span(mid, end).trim_start(other), None); + assert_eq!(span(start, end).trim_start(other), None); + assert_eq!(span(before, end).trim_start(other), None); + + assert_eq!(span(start, mid).trim_start(other), None); + assert_eq!(span(before, mid).trim_start(other), None); + + assert_eq!(span(before, start).trim_start(other), None); + + assert_eq!(span(well_before, before).trim_start(other), None); +} diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 0ed1f67bb82..75cac6c7992 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -270,15 +270,15 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> { fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> { // only print integers - match (ct.kind(), ct.ty().kind()) { - (ty::ConstKind::Value(ty::ValTree::Leaf(scalar)), ty::Int(_) | ty::Uint(_)) => { + match ct.kind() { + ty::ConstKind::Value(ty, ty::ValTree::Leaf(scalar)) if ty.is_integral() => { // The `pretty_print_const` formatting depends on -Zverbose-internals // flag, so we cannot reuse it here. - let signed = matches!(ct.ty().kind(), ty::Int(_)); + let signed = matches!(ty.kind(), ty::Int(_)); write!( self, "{:#?}", - ty::ConstInt::new(scalar, signed, ct.ty().is_ptr_sized_integral()) + ty::ConstInt::new(scalar, signed, ty.is_ptr_sized_integral()) )?; } _ => self.write_str("_")?, diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 57b1542ff5a..55479bce6fc 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -541,8 +541,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> { // We only mangle a typed value if the const can be evaluated. let ct = ct.normalize(self.tcx, ty::ParamEnv::reveal_all()); - match ct.kind() { - ty::ConstKind::Value(_) => {} + let (ct_ty, valtree) = match ct.kind() { + ty::ConstKind::Value(ty, val) => (ty, val), // Placeholders (should be demangled as `_`). // NOTE(eddyb) despite `Unevaluated` having a `DefId` (and therefore @@ -559,7 +559,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { self.push("p"); return Ok(()); } - } + }; if let Some(&i) = self.consts.get(&ct) { self.print_backref(i)?; @@ -567,16 +567,15 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { } let start = self.out.len(); - let ty = ct.ty(); - match ty.kind() { + match ct_ty.kind() { ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => { - ty.print(self)?; + ct_ty.print(self)?; let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all()); // Negative integer values are mangled using `n` as a "sign prefix". - if let ty::Int(ity) = ty.kind() { + if let ty::Int(ity) = ct_ty.kind() { let val = Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(bits) as i128; if val < 0 { @@ -598,40 +597,32 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { match inner_ty.kind() { ty::Str if mutbl.is_not() => { - match ct.kind() { - ty::ConstKind::Value(valtree) => { - let slice = - valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| { - bug!( - "expected to get raw bytes from valtree {:?} for type {:}", - valtree, ty - ) - }); - let s = std::str::from_utf8(slice) - .expect("non utf8 str from MIR interpreter"); - - self.push("e"); - - // FIXME(eddyb) use a specialized hex-encoding loop. - for byte in s.bytes() { - let _ = write!(self.out, "{byte:02x}"); - } - - self.push("_"); - } - - _ => { - bug!("symbol_names: unsupported `&str` constant: {:?}", ct); - } + let slice = + valtree.try_to_raw_bytes(self.tcx(), ct_ty).unwrap_or_else(|| { + bug!( + "expected to get raw bytes from valtree {:?} for type {:}", + valtree, + ct_ty + ) + }); + let s = + std::str::from_utf8(slice).expect("non utf8 str from MIR interpreter"); + + self.push("e"); + + // FIXME(eddyb) use a specialized hex-encoding loop. + for byte in s.bytes() { + let _ = write!(self.out, "{byte:02x}"); } + + self.push("_"); } _ => { - let pointee_ty = ct - .ty() + let pointee_ty = ct_ty .builtin_deref(true) .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); + let dereferenced_const = + ty::Const::new_value(self.tcx, valtree, pointee_ty); dereferenced_const.print(self)?; } } @@ -649,7 +640,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { Ok(()) }; - match *ct.ty().kind() { + match *ct_ty.kind() { ty::Array(..) | ty::Slice(_) => { self.push("A"); print_field_list(self)?; @@ -698,7 +689,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { } } _ => { - bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty(), ct); + bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct_ty, ct); } } diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 666efd9deca..737e9a8eab0 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -256,29 +256,6 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ty::is_transparent(self) } - pub fn offset_of_subfield<C, I>(self, cx: &C, indices: I) -> Size - where - Ty: TyAbiInterface<'a, C>, - I: Iterator<Item = (VariantIdx, FieldIdx)>, - { - let mut layout = self; - let mut offset = Size::ZERO; - - for (variant, field) in indices { - layout = layout.for_variant(cx, variant); - let index = field.index(); - offset += layout.fields.offset(index); - layout = layout.field(cx, index); - assert!( - layout.is_sized(), - "offset of unsized field (type {:?}) cannot be computed statically", - layout.ty - ); - } - - offset - } - /// Finds the one field that is not a 1-ZST. /// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields. pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(usize, Self)> diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 46c83be9d95..ecc91ab9a31 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -41,17 +41,13 @@ const RUST_LIB_DIR: &str = "rustlib"; /// /// For example: `target_sysroot_path("/usr", "x86_64-unknown-linux-gnu")` => /// `"lib*/rustlib/x86_64-unknown-linux-gnu"`. -pub fn target_rustlib_path(sysroot: &Path, target_triple: &str) -> PathBuf { - let libdir = find_libdir(sysroot); - PathBuf::from_iter([ - Path::new(libdir.as_ref()), - Path::new(RUST_LIB_DIR), - Path::new(target_triple), - ]) +pub fn relative_target_rustlib_path(sysroot: &Path, target_triple: &str) -> PathBuf { + let libdir = find_relative_libdir(sysroot); + Path::new(libdir.as_ref()).join(RUST_LIB_DIR).join(target_triple) } /// The name of the directory rustc expects libraries to be located. -fn find_libdir(sysroot: &Path) -> std::borrow::Cow<'static, str> { +fn find_relative_libdir(sysroot: &Path) -> std::borrow::Cow<'static, str> { // FIXME: This is a quick hack to make the rustc binary able to locate // Rust libraries in Linux environments where libraries might be installed // to lib64/lib32. This would be more foolproof by basing the sysroot off diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 83ee63e2cf2..fe07d116726 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -3367,7 +3367,7 @@ impl Target { // Additionally look in the sysroot under `lib/rustlib/<triple>/target.json` // as a fallback. - let rustlib_path = crate::target_rustlib_path(sysroot, target_triple); + let rustlib_path = crate::relative_target_rustlib_path(sysroot, target_triple); let p = PathBuf::from_iter([ Path::new(sysroot), Path::new(&rustlib_path), diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index fc852293dff..c95649e2ffb 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -1,14 +1,12 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _; -use crate::traits::{self, ObligationCtxt, SelectionContext}; +use crate::traits::{self, Obligation, ObligationCause, ObligationCtxt, SelectionContext}; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; -use rustc_infer::traits::Obligation; use rustc_macros::extension; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse}; use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_middle::ty::{GenericArg, Upcast}; use rustc_span::DUMMY_SP; @@ -94,7 +92,7 @@ impl<'tcx> InferCtxt<'tcx> { ty::TraitRef::new(self.tcx, trait_def_id, [ty]), )) { Ok(Some(selection)) => { - let ocx = ObligationCtxt::new(self); + let ocx = ObligationCtxt::new_with_diagnostics(self); ocx.register_obligations(selection.nested_obligations()); Some(ocx.select_all_or_error()) } diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 521e4ef0c9e..381da6f7e2a 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -23,7 +23,6 @@ #![feature(extract_if)] #![feature(if_let_guard)] #![feature(let_chains)] -#![feature(option_take_if)] #![feature(never_type)] #![feature(type_alias_impl_trait)] #![recursion_limit = "512"] // For rustdoc diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index 5e0d7da4f06..5f986e22f51 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -1,3 +1,4 @@ +use crate::traits::ScrubbedTraitError; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{InferCtxt, RegionResolutionError}; use rustc_macros::extension; @@ -27,7 +28,7 @@ impl<'tcx> InferCtxt<'tcx> { ), ty, ) - .map_err(|_| NoSolution) + .map_err(|_: Vec<ScrubbedTraitError<'tcx>>| NoSolution) } else { Ok(ty) } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index aae6fa9f635..b51efd339c4 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -714,7 +714,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { }; // Do not consider built-in object impls for non-object-safe types. - if bounds.principal_def_id().is_some_and(|def_id| !tcx.check_is_object_safe(def_id)) { + if bounds.principal_def_id().is_some_and(|def_id| !tcx.is_object_safe(def_id)) { return; } 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 48acf2a4e99..98f98d9992d 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -726,7 +726,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> { ) .expect("expected to be able to unify goal projection with dyn's projection"), ); - proj.term.ty().unwrap() + proj.term.expect_type() } else { ty.super_fold_with(self) } 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 690c1797f23..0e0b9e98339 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -444,7 +444,7 @@ pub(in crate::solve) fn instantiate_canonical_state<'tcx, T: TypeFoldable<TyCtxt infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)).into() } ty::GenericArgKind::Type(_) => infcx.next_ty_var(span).into(), - ty::GenericArgKind::Const(ct) => infcx.next_const_var(ct.ty(), span).into(), + ty::GenericArgKind::Const(_) => infcx.next_const_var(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 f18f1f4f8f0..b522022c206 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -37,11 +37,11 @@ pub(super) mod canonical; mod probe; mod select; -pub struct EvalCtxt< - 'a, +pub struct EvalCtxt<'a, Infcx, I = <Infcx as InferCtxtLike>::Interner> +where Infcx: InferCtxtLike<Interner = I>, - I: Interner = <Infcx as InferCtxtLike>::Interner, -> { + I: Interner, +{ /// The inference context that backs (mostly) inference and placeholder terms /// instantiated while solving goals. /// @@ -609,8 +609,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ty } - pub(super) fn next_const_infer(&mut self, ty: Ty<'tcx>) -> ty::Const<'tcx> { - let ct = self.infcx.next_const_var(ty, DUMMY_SP); + pub(super) fn next_const_infer(&mut self) -> ty::Const<'tcx> { + let ct = self.infcx.next_const_var(DUMMY_SP); self.inspect.add_var_value(ct); ct } @@ -620,7 +620,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(super) fn next_term_infer_of_kind(&mut self, kind: ty::Term<'tcx>) -> ty::Term<'tcx> { match kind.unpack() { ty::TermKind::Ty(_) => self.next_ty_infer().into(), - ty::TermKind::Const(ct) => self.next_const_infer(ct.ty()).into(), + ty::TermKind::Const(_) => self.next_const_infer().into(), } } @@ -1037,14 +1037,19 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &self, param_env: ty::ParamEnv<'tcx>, unevaluated: ty::UnevaluatedConst<'tcx>, - ty: Ty<'tcx>, ) -> Option<ty::Const<'tcx>> { use rustc_middle::mir::interpret::ErrorHandled; match self.infcx.const_eval_resolve(param_env, unevaluated, DUMMY_SP) { - Ok(Some(val)) => Some(ty::Const::new_value(self.interner(), val, ty)), + Ok(Some(val)) => Some(ty::Const::new_value( + self.interner(), + val, + self.interner() + .type_of(unevaluated.def) + .instantiate(self.interner(), unevaluated.args), + )), Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None, Err(ErrorHandled::Reported(e, _)) => { - Some(ty::Const::new_error(self.interner(), e.into(), ty)) + Some(ty::Const::new_error(self.interner(), e.into())) } } } @@ -1124,7 +1129,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAliasWithInfer<'_, '_, 'tcx> { fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { match ct.kind() { ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => { - let infer_ct = self.ecx.next_const_infer(ct.ty()); + let infer_ct = self.ecx.next_const_infer(); let normalizes_to = ty::PredicateKind::AliasRelate( ct.into(), infer_ct.into(), diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index d28cf834032..dc13941e5d7 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -1,3 +1,4 @@ +use std::marker::PhantomData; use std::mem; use std::ops::ControlFlow; @@ -5,14 +6,16 @@ use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause}; use rustc_infer::traits::{ - self, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation, - ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError, TraitEngine, + self, FromSolverError, MismatchedProjectionTypes, Obligation, ObligationCause, + ObligationCauseCode, PredicateObligation, SelectionError, TraitEngine, }; use rustc_middle::bug; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::sym; +use crate::traits::{FulfillmentError, FulfillmentErrorCode, ScrubbedTraitError}; + use super::eval_ctxt::GenerateProofTree; use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor}; use super::{Certainty, InferCtxtEvalExt}; @@ -28,7 +31,7 @@ use super::{Certainty, InferCtxtEvalExt}; /// /// It is also likely that we want to use slightly different datastructures /// here as this will have to deal with far more root goals than `evaluate_all`. -pub struct FulfillmentCtxt<'tcx> { +pub struct FulfillmentCtxt<'tcx, E: 'tcx> { obligations: ObligationStorage<'tcx>, /// The snapshot in which this context was created. Using the context @@ -36,6 +39,7 @@ pub struct FulfillmentCtxt<'tcx> { /// gets rolled back. Because of this we explicitly check that we only /// use the context in exactly this snapshot. usable_in_snapshot: usize, + _errors: PhantomData<E>, } #[derive(Default)] @@ -89,8 +93,8 @@ impl<'tcx> ObligationStorage<'tcx> { } } -impl<'tcx> FulfillmentCtxt<'tcx> { - pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx> { +impl<'tcx, E: 'tcx> FulfillmentCtxt<'tcx, E> { + pub fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentCtxt<'tcx, E> { assert!( infcx.next_trait_solver(), "new trait solver fulfillment context created when \ @@ -99,6 +103,7 @@ impl<'tcx> FulfillmentCtxt<'tcx> { FulfillmentCtxt { obligations: Default::default(), usable_in_snapshot: infcx.num_open_snapshots(), + _errors: PhantomData, } } @@ -118,7 +123,10 @@ impl<'tcx> FulfillmentCtxt<'tcx> { } } -impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { +impl<'tcx, E> TraitEngine<'tcx, E> for FulfillmentCtxt<'tcx, E> +where + E: FromSolverError<'tcx, NextSolverError<'tcx>>, +{ #[instrument(level = "trace", skip(self, infcx))] fn register_predicate_obligation( &mut self, @@ -129,24 +137,22 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { self.obligations.register(obligation); } - fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { - let mut errors: Vec<_> = self - .obligations + fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> { + self.obligations .pending .drain(..) - .map(|obligation| fulfillment_error_for_stalled(infcx, obligation)) - .collect(); - - errors.extend(self.obligations.overflowed.drain(..).map(|obligation| FulfillmentError { - obligation: find_best_leaf_obligation(infcx, &obligation, true), - code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) }, - root_obligation: obligation, - })); - - errors + .map(|obligation| NextSolverError::Ambiguity(obligation)) + .chain( + self.obligations + .overflowed + .drain(..) + .map(|obligation| NextSolverError::Overflow(obligation)), + ) + .map(|e| E::from_solver_error(infcx, e)) + .collect() } - fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { + fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> { assert_eq!(self.usable_in_snapshot, infcx.num_open_snapshots()); let mut errors = Vec::new(); for i in 0.. { @@ -164,7 +170,10 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { let (changed, certainty) = match result { Ok(result) => result, Err(NoSolution) => { - errors.push(fulfillment_error_for_no_solution(infcx, obligation)); + errors.push(E::from_solver_error( + infcx, + NextSolverError::TrueError(obligation), + )); continue; } }; @@ -195,6 +204,39 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> { } } +pub enum NextSolverError<'tcx> { + TrueError(PredicateObligation<'tcx>), + Ambiguity(PredicateObligation<'tcx>), + Overflow(PredicateObligation<'tcx>), +} + +impl<'tcx> FromSolverError<'tcx, NextSolverError<'tcx>> for FulfillmentError<'tcx> { + fn from_solver_error(infcx: &InferCtxt<'tcx>, error: NextSolverError<'tcx>) -> Self { + match error { + NextSolverError::TrueError(obligation) => { + fulfillment_error_for_no_solution(infcx, obligation) + } + NextSolverError::Ambiguity(obligation) => { + fulfillment_error_for_stalled(infcx, obligation) + } + NextSolverError::Overflow(obligation) => { + fulfillment_error_for_overflow(infcx, obligation) + } + } + } +} + +impl<'tcx> FromSolverError<'tcx, NextSolverError<'tcx>> for ScrubbedTraitError<'tcx> { + fn from_solver_error(_infcx: &InferCtxt<'tcx>, error: NextSolverError<'tcx>) -> Self { + match error { + NextSolverError::TrueError(_) => ScrubbedTraitError::TrueError, + NextSolverError::Ambiguity(_) | NextSolverError::Overflow(_) => { + ScrubbedTraitError::Ambiguity + } + } + } +} + fn fulfillment_error_for_no_solution<'tcx>( infcx: &InferCtxt<'tcx>, root_obligation: PredicateObligation<'tcx>, @@ -280,6 +322,17 @@ fn fulfillment_error_for_stalled<'tcx>( } } +fn fulfillment_error_for_overflow<'tcx>( + infcx: &InferCtxt<'tcx>, + root_obligation: PredicateObligation<'tcx>, +) -> FulfillmentError<'tcx> { + FulfillmentError { + obligation: find_best_leaf_obligation(infcx, &root_obligation, true), + code: FulfillmentErrorCode::Ambiguity { overflow: Some(true) }, + root_obligation, + } +} + fn find_best_leaf_obligation<'tcx>( infcx: &InferCtxt<'tcx>, obligation: &PredicateObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 1f27978e5a6..19c95dad48c 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -208,7 +208,7 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => { let unconstrained_term = match term.unpack() { ty::TermKind::Ty(_) => infcx.next_ty_var(span).into(), - ty::TermKind::Const(ct) => infcx.next_const_var(ct.ty(), span).into(), + ty::TermKind::Const(_) => infcx.next_const_var(span).into(), }; let goal = goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term }); diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index f9febd290fe..c47b0194964 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -40,7 +40,7 @@ mod search_graph; mod trait_goals; pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt}; -pub use fulfill::FulfillmentCtxt; +pub use fulfill::{FulfillmentCtxt, NextSolverError}; pub(crate) use normalize::deeply_normalize_for_diagnostics; pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; @@ -133,7 +133,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> { - if self.interner().check_is_object_safe(trait_def_id) { + if self.interner().is_object_safe(trait_def_id) { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { Err(NoSolution) @@ -169,7 +169,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { // FIXME(generic_const_exprs): Implement handling for generic // const expressions here. - if let Some(_normalized) = self.try_const_eval_resolve(param_env, uv, ct.ty()) { + if let Some(_normalized) = self.try_const_eval_resolve(param_env, uv) { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) @@ -178,7 +178,9 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { ty::ConstKind::Infer(_) => { self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) } - ty::ConstKind::Placeholder(_) | ty::ConstKind::Value(_) | ty::ConstKind::Error(_) => { + ty::ConstKind::Placeholder(_) + | ty::ConstKind::Value(_, _) + | ty::ConstKind::Error(_) => { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } // We can freely ICE here as: @@ -198,29 +200,37 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { ) -> QueryResult<'tcx> { let (ct, ty) = goal.predicate; - // FIXME(BoxyUwU): Really we should not be calling `ct.ty()` for any variant - // other than `ConstKind::Value`. Unfortunately this would require looking in the - // env for any `ConstArgHasType` assumptions for parameters and placeholders. I - // have not yet gotten around to implementing this though. - // - // We do still stall on infer vars though as otherwise a goal like: - // `ConstArgHasType(?x: usize, usize)` can succeed even though it might later - // get unified with some const that is not of type `usize`. - match ct.kind() { + let ct_ty = match ct.kind() { // FIXME: Ignore effect vars because canonicalization doesn't handle them correctly // and if we stall on the var then we wind up creating ambiguity errors in a probe // for this goal which contains an effect var. Which then ends up ICEing. - ty::ConstKind::Infer(ty::InferConst::Var(_)) => { - self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS) + ty::ConstKind::Infer(ty::InferConst::EffectVar(_)) => { + return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); + } + ty::ConstKind::Infer(_) => { + return self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); } ty::ConstKind::Error(_) => { - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } - _ => { - self.eq(goal.param_env, ct.ty(), ty)?; - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + ty::ConstKind::Unevaluated(uv) => { + self.interner().type_of(uv.def).instantiate(self.interner(), uv.args) } - } + ty::ConstKind::Expr(_) => unimplemented!( + "`feature(generic_const_exprs)` is not supported in the new trait solver" + ), + ty::ConstKind::Param(_) => { + unreachable!("`ConstKind::Param` should have been canonicalized to `Placeholder`") + } + ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct), + ty::ConstKind::Value(ty, _) => ty, + ty::ConstKind::Placeholder(placeholder) => { + placeholder.find_const_ty_from_env(goal.param_env) + } + }; + + self.eq(goal.param_env, ct_ty, ty)?; + self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index 5d5161e092e..f42edebfcc4 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -1,24 +1,27 @@ +use std::fmt::Debug; +use std::marker::PhantomData; + use crate::traits::error_reporting::{OverflowCause, TypeErrCtxtExt}; use crate::traits::query::evaluate_obligation::InferCtxtExt; -use crate::traits::{BoundVarReplacer, PlaceholderReplacer}; +use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::at::At; use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::TraitEngineExt; -use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine}; +use rustc_infer::traits::{FromSolverError, Obligation, TraitEngine}; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex}; use rustc_middle::ty::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; -use super::FulfillmentCtxt; +use super::{FulfillmentCtxt, NextSolverError}; /// Deeply normalize all aliases in `value`. This does not handle inference and expects /// its input to be already fully resolved. -pub fn deeply_normalize<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( - at: At<'_, 'tcx>, - value: T, -) -> Result<T, Vec<FulfillmentError<'tcx>>> { +pub fn deeply_normalize<'tcx, T, E>(at: At<'_, 'tcx>, value: T) -> Result<T, Vec<E>> +where + T: TypeFoldable<TyCtxt<'tcx>>, + E: FromSolverError<'tcx, NextSolverError<'tcx>>, +{ assert!(!value.has_escaping_bound_vars()); deeply_normalize_with_skipped_universes(at, value, vec![]) } @@ -29,29 +32,35 @@ pub fn deeply_normalize<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( /// Additionally takes a list of universes which represents the binders which have been /// entered before passing `value` to the function. This is currently needed for /// `normalize_erasing_regions`, which skips binders as it walks through a type. -pub fn deeply_normalize_with_skipped_universes<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( +pub fn deeply_normalize_with_skipped_universes<'tcx, T, E>( at: At<'_, 'tcx>, value: T, universes: Vec<Option<UniverseIndex>>, -) -> Result<T, Vec<FulfillmentError<'tcx>>> { +) -> Result<T, Vec<E>> +where + T: TypeFoldable<TyCtxt<'tcx>>, + E: FromSolverError<'tcx, NextSolverError<'tcx>>, +{ let fulfill_cx = FulfillmentCtxt::new(at.infcx); - let mut folder = NormalizationFolder { at, fulfill_cx, depth: 0, universes }; + let mut folder = + NormalizationFolder { at, fulfill_cx, depth: 0, universes, _errors: PhantomData }; value.try_fold_with(&mut folder) } -struct NormalizationFolder<'me, 'tcx> { +struct NormalizationFolder<'me, 'tcx, E> { at: At<'me, 'tcx>, - fulfill_cx: FulfillmentCtxt<'tcx>, + fulfill_cx: FulfillmentCtxt<'tcx, E>, depth: usize, universes: Vec<Option<UniverseIndex>>, + _errors: PhantomData<E>, } -impl<'tcx> NormalizationFolder<'_, 'tcx> { - fn normalize_alias_ty( - &mut self, - alias_ty: Ty<'tcx>, - ) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> { +impl<'tcx, E> NormalizationFolder<'_, 'tcx, E> +where + E: FromSolverError<'tcx, NextSolverError<'tcx>>, +{ + fn normalize_alias_ty(&mut self, alias_ty: Ty<'tcx>) -> Result<Ty<'tcx>, Vec<E>> { assert!(matches!(alias_ty.kind(), ty::Alias(..))); let infcx = self.at.infcx; @@ -100,9 +109,8 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> { fn normalize_unevaluated_const( &mut self, - ty: Ty<'tcx>, uv: ty::UnevaluatedConst<'tcx>, - ) -> Result<ty::Const<'tcx>, Vec<FulfillmentError<'tcx>>> { + ) -> Result<ty::Const<'tcx>, Vec<E>> { let infcx = self.at.infcx; let tcx = infcx.tcx; let recursion_limit = tcx.recursion_limit(); @@ -117,7 +125,7 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> { self.depth += 1; - let new_infer_ct = infcx.next_const_var(ty, self.at.cause.span); + let new_infer_ct = infcx.next_const_var(self.at.cause.span); let obligation = Obligation::new( tcx, self.at.cause.clone(), @@ -134,7 +142,7 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> { let ct = infcx.resolve_vars_if_possible(new_infer_ct); ct.try_fold_with(self)? } else { - ty::Const::new_unevaluated(tcx, uv, ty).try_super_fold_with(self)? + ty::Const::new_unevaluated(tcx, uv).try_super_fold_with(self)? }; self.depth -= 1; @@ -142,8 +150,11 @@ impl<'tcx> NormalizationFolder<'_, 'tcx> { } } -impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> { - type Error = Vec<FulfillmentError<'tcx>>; +impl<'tcx, E> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx, E> +where + E: FromSolverError<'tcx, NextSolverError<'tcx>> + Debug, +{ + type Error = Vec<E>; fn interner(&self) -> TyCtxt<'tcx> { self.at.infcx.tcx @@ -202,7 +213,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> { if uv.has_escaping_bound_vars() { let (uv, mapped_regions, mapped_types, mapped_consts) = BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, uv); - let result = ensure_sufficient_stack(|| self.normalize_unevaluated_const(ct.ty(), uv))?; + let result = ensure_sufficient_stack(|| self.normalize_unevaluated_const(uv))?; Ok(PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, @@ -212,7 +223,7 @@ impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx> { result, )) } else { - ensure_sufficient_stack(|| self.normalize_unevaluated_const(ct.ty(), uv)) + ensure_sufficient_stack(|| self.normalize_unevaluated_const(uv)) } } } @@ -243,7 +254,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_, ty, vec![None; ty.outer_exclusive_binder().as_usize()], ) - .unwrap_or_else(|_| ty.super_fold_with(self)) + .unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ty.super_fold_with(self)) } fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { @@ -252,6 +263,6 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for DeeplyNormalizeForDiagnosticsFolder<'_, ct, vec![None; ct.outer_exclusive_binder().as_usize()], ) - .unwrap_or_else(|_| ct.super_fold_with(self)) + .unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ct.super_fold_with(self)) } } 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 362c4072278..a6e4b6ff4a8 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 @@ -12,10 +12,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { if let Some(normalized_const) = self.try_const_eval_resolve( goal.param_env, ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args), - self.interner() - .type_of(goal.predicate.alias.def_id) - .no_bound_vars() - .expect("const ty should not rely on other generics"), ) { self.instantiate_normalizes_to_term(goal, normalized_const.into()); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) 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 8c63bd824bc..787f08a084e 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -201,13 +201,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { let error_response = |ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, reason| { let guar = tcx.dcx().span_delayed_bug(tcx.def_span(assoc_def.item.def_id), reason); let error_term = match assoc_def.item.kind { - ty::AssocKind::Const => ty::Const::new_error( - tcx, - guar, - tcx.type_of(goal.predicate.def_id()) - .instantiate(tcx, goal.predicate.alias.args), - ) - .into(), + ty::AssocKind::Const => ty::Const::new_error(tcx, guar).into(), ty::AssocKind::Type => Ty::new_error(tcx, guar).into(), // This makes no sense... ty::AssocKind::Fn => span_bug!( @@ -253,7 +247,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ty::EarlyBinder::bind( ty::Const::new_error_with_message( tcx, - tcx.type_of(assoc_def.item.def_id).instantiate_identity(), DUMMY_SP, "associated const projection is not supported yet", ) diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs index 67ec2f3be48..82464470b2a 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs @@ -17,7 +17,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ) -> QueryResult<'tcx> { let tcx = self.interner(); let opaque_ty = goal.predicate.alias; - let expected = goal.predicate.term.ty().expect("no such thing as an opaque const"); + let expected = goal.predicate.term.as_type().expect("no such thing as an opaque const"); match (goal.param_env.reveal(), self.solver_mode()) { (Reveal::UserFacing, SolverMode::Normal) => { diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index e93d5c96b88..a741f488901 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -789,7 +789,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { let Goal { predicate: (a_ty, _), .. } = goal; // Can only unsize to an object-safe trait. - if b_data.principal_def_id().is_some_and(|def_id| !tcx.check_is_object_safe(def_id)) { + if b_data.principal_def_id().is_some_and(|def_id| !tcx.is_object_safe(def_id)) { return Err(NoSolution); } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 1ea207cc375..1d32ef2ccd9 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -553,7 +553,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { } fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'tcx>) -> bool { - if let Some(ty) = p.term().skip_binder().ty() { + if let Some(ty) = p.term().skip_binder().as_type() { matches!(ty.kind(), ty::Alias(ty::Projection, proj) if proj == &p.skip_binder().projection_term.expect_ty(self.tcx)) } else { false @@ -765,7 +765,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { unevaluated, obligation.cause.span, ) { - Ok(Some(valtree)) => Ok(ty::Const::new_value(selcx.tcx(),valtree, c.ty())), + Ok(Some(valtree)) => Ok(ty::Const::new_value(selcx.tcx(),valtree, self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args))), Ok(None) => { let tcx = self.tcx; let reported = diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index ebdb032dc0e..1ef2f26cd09 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -11,6 +11,7 @@ use crate::solve::{deeply_normalize_for_diagnostics, inspect}; use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::NormalizeExt; use crate::traits::SkipLeakCheck; +use crate::traits::{util, FulfillmentErrorCode}; use crate::traits::{ Obligation, ObligationCause, PredicateObligation, PredicateObligations, SelectionContext, }; @@ -19,7 +20,6 @@ use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::{util, FulfillmentErrorCode}; use rustc_middle::bug; use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal}; @@ -360,7 +360,7 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>( let infcx = selcx.infcx; if infcx.next_trait_solver() { - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); ocx.register_obligations(obligations.iter().cloned()); let errors_and_ambiguities = ocx.select_all_or_error(); // We only care about the obligations that are *definitely* true errors. @@ -529,7 +529,6 @@ fn plug_infer_with_placeholders<'tcx>( ty::Const::new_placeholder( self.infcx.tcx, ty::Placeholder { universe: self.universe, bound: self.next_var() }, - ct.ty(), ), ) else { @@ -924,11 +923,12 @@ where } } - ty::Alias(kind @ (ty::Projection | ty::Inherent | ty::Weak), ..) => { - if ty.has_type_flags(ty::TypeFlags::HAS_TY_PARAM) { - bug!("unexpected ty param in alias ty"); - } - + // A rigid alias may normalize to anything. + // * If it references an infer var, placeholder or bound ty, it may + // normalize to that, so we have to treat it as an uncovered ty param. + // * Otherwise it may normalize to any non-type-generic type + // be it local or non-local. + ty::Alias(kind, _) => { if ty.has_type_flags( ty::TypeFlags::HAS_TY_PLACEHOLDER | ty::TypeFlags::HAS_TY_BOUND @@ -948,7 +948,24 @@ where } } } else { - ControlFlow::Continue(()) + // Regarding *opaque types* specifically, we choose to treat them as non-local, + // even those that appear within the same crate. This seems somewhat surprising + // at first, but makes sense when you consider that opaque types are supposed + // to hide the underlying type *within the same crate*. When an opaque type is + // used from outside the module where it is declared, it should be impossible to + // observe anything about it other than the traits that it implements. + // + // The alternative would be to look at the underlying type to determine whether + // or not the opaque type itself should be considered local. + // + // However, this could make it a breaking change to switch the underlying hidden + // type from a local type to a remote type. This would violate the rule that + // opaque types should be completely opaque apart from the traits that they + // implement, so we don't use this behavior. + // Addendum: Moreover, revealing the underlying type is likely to cause cycle + // errors as we rely on coherence / the specialization graph during typeck. + + self.found_non_local_ty(ty) } } @@ -990,35 +1007,6 @@ where // auto trait impl applies. There will never be multiple impls, so we can just // act as if it were a local type here. ty::CoroutineWitness(..) => ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty)), - ty::Alias(ty::Opaque, ..) => { - // This merits some explanation. - // Normally, opaque types are not involved when performing - // coherence checking, since it is illegal to directly - // implement a trait on an opaque type. However, we might - // end up looking at an opaque type during coherence checking - // if an opaque type gets used within another type (e.g. as - // the type of a field) when checking for auto trait or `Sized` - // impls. This requires us to decide whether or not an opaque - // type should be considered 'local' or not. - // - // We choose to treat all opaque types as non-local, even - // those that appear within the same crate. This seems - // somewhat surprising at first, but makes sense when - // you consider that opaque types are supposed to hide - // the underlying type *within the same crate*. When an - // opaque type is used from outside the module - // where it is declared, it should be impossible to observe - // anything about it other than the traits that it implements. - // - // The alternative would be to look at the underlying type - // to determine whether or not the opaque type itself should - // be considered local. However, this could make it a breaking change - // to switch the underlying ('defining') type from a local type - // to a remote type. This would violate the rule that opaque - // types should be completely opaque apart from the traits - // that they implement, so we don't use this behavior. - self.found_non_local_ty(ty) - } }; // A bit of a hack, the `OrphanChecker` is only used to visit a `TraitRef`, so // the first type we visit is always the self type. diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 8348482386f..f93bd0a396d 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -34,7 +34,7 @@ pub fn is_const_evaluatable<'tcx>( ty::ConstKind::Param(_) | ty::ConstKind::Bound(_, _) | ty::ConstKind::Placeholder(_) - | ty::ConstKind::Value(_) + | ty::ConstKind::Value(_, _) | ty::ConstKind::Error(_) => return Ok(()), ty::ConstKind::Infer(_) => return Err(NotConstEvaluatable::MentionsInfer), }; @@ -173,8 +173,7 @@ fn satisfied_from_param_env<'tcx>( debug!("is_const_evaluatable: candidate={:?}", c); if self.infcx.probe(|_| { let ocx = ObligationCtxt::new(self.infcx); - ocx.eq(&ObligationCause::dummy(), self.param_env, c.ty(), self.ct.ty()).is_ok() - && ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct).is_ok() + ocx.eq(&ObligationCause::dummy(), self.param_env, c, self.ct).is_ok() && ocx.select_all_or_error().is_empty() }) { self.single_match = match self.single_match { @@ -215,7 +214,6 @@ fn satisfied_from_param_env<'tcx>( if let Some(Ok(c)) = single_match { let ocx = ObligationCtxt::new(infcx); - assert!(ocx.eq(&ObligationCause::dummy(), param_env, c.ty(), ct.ty()).is_ok()); assert!(ocx.eq(&ObligationCause::dummy(), param_env, c, ct).is_ok()); assert!(ocx.select_all_or_error().is_empty()); return true; diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 4684c7171d8..811f61d2bf3 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -1,13 +1,16 @@ use std::cell::RefCell; use std::fmt::Debug; -use super::FulfillmentContext; -use super::TraitEngine; +use super::{FromSolverError, TraitEngine}; +use super::{FulfillmentContext, ScrubbedTraitError}; use crate::regions::InferCtxtRegionExt; use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt; +use crate::solve::NextSolverError; use crate::traits::error_reporting::TypeErrCtxtExt; +use crate::traits::fulfill::OldSolverError; use crate::traits::NormalizeExt; use crate::traits::StructurallyNormalizeExt; +use crate::traits::{FulfillmentError, Obligation, ObligationCause, PredicateObligation}; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -18,9 +21,6 @@ use rustc_infer::infer::canonical::{ use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::RegionResolutionError; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; -use rustc_infer::traits::{ - FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _, -}; use rustc_macros::extension; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::traits::query::NoSolution; @@ -30,8 +30,11 @@ use rustc_middle::ty::Upcast; use rustc_middle::ty::Variance; use rustc_middle::ty::{self, Ty, TyCtxt}; -#[extension(pub trait TraitEngineExt<'tcx>)] -impl<'tcx> dyn TraitEngine<'tcx> { +#[extension(pub trait TraitEngineExt<'tcx, E>)] +impl<'tcx, E> dyn TraitEngine<'tcx, E> +where + E: FromSolverError<'tcx, NextSolverError<'tcx>> + FromSolverError<'tcx, OldSolverError<'tcx>>, +{ fn new(infcx: &InferCtxt<'tcx>) -> Box<Self> { if infcx.next_trait_solver() { Box::new(NextFulfillmentCtxt::new(infcx)) @@ -49,16 +52,27 @@ impl<'tcx> dyn TraitEngine<'tcx> { /// Used if you want to have pleasant experience when dealing /// with obligations outside of hir or mir typeck. -pub struct ObligationCtxt<'a, 'tcx> { +pub struct ObligationCtxt<'a, 'tcx, E = ScrubbedTraitError<'tcx>> { pub infcx: &'a InferCtxt<'tcx>, - engine: RefCell<Box<dyn TraitEngine<'tcx>>>, + engine: RefCell<Box<dyn TraitEngine<'tcx, E>>>, } -impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { +impl<'a, 'tcx> ObligationCtxt<'a, 'tcx, FulfillmentError<'tcx>> { + pub fn new_with_diagnostics(infcx: &'a InferCtxt<'tcx>) -> Self { + Self { infcx, engine: RefCell::new(<dyn TraitEngine<'tcx, _>>::new(infcx)) } + } +} + +impl<'a, 'tcx> ObligationCtxt<'a, 'tcx, ScrubbedTraitError<'tcx>> { pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { - Self { infcx, engine: RefCell::new(<dyn TraitEngine<'_>>::new(infcx)) } + Self { infcx, engine: RefCell::new(<dyn TraitEngine<'tcx, _>>::new(infcx)) } } +} +impl<'a, 'tcx, E> ObligationCtxt<'a, 'tcx, E> +where + E: 'tcx, +{ pub fn register_obligation(&self, obligation: PredicateObligation<'tcx>) { self.engine.borrow_mut().register_predicate_obligation(self.infcx, obligation); } @@ -110,26 +124,6 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { self.register_infer_ok_obligations(infer_ok) } - pub fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>( - &self, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: T, - ) -> Result<T, Vec<FulfillmentError<'tcx>>> { - self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut()) - } - - pub fn structurally_normalize( - &self, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: Ty<'tcx>, - ) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> { - self.infcx - .at(cause, param_env) - .structurally_normalize(value, &mut **self.engine.borrow_mut()) - } - pub fn eq<T: ToTrace<'tcx>>( &self, cause: &ObligationCause<'tcx>, @@ -186,12 +180,12 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { } #[must_use] - pub fn select_where_possible(&self) -> Vec<FulfillmentError<'tcx>> { + pub fn select_where_possible(&self) -> Vec<E> { self.engine.borrow_mut().select_where_possible(self.infcx) } #[must_use] - pub fn select_all_or_error(&self) -> Vec<FulfillmentError<'tcx>> { + pub fn select_all_or_error(&self) -> Vec<E> { self.engine.borrow_mut().select_all_or_error(self.infcx) } @@ -235,7 +229,9 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { ) -> Vec<RegionResolutionError<'tcx>> { self.infcx.resolve_regions(outlives_env) } +} +impl<'tcx> ObligationCtxt<'_, 'tcx, FulfillmentError<'tcx>> { pub fn assumed_wf_types_and_report_errors( &self, param_env: ty::ParamEnv<'tcx>, @@ -244,12 +240,35 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { self.assumed_wf_types(param_env, def_id) .map_err(|errors| self.infcx.err_ctxt().report_fulfillment_errors(errors)) } +} + +impl<'tcx> ObligationCtxt<'_, 'tcx, ScrubbedTraitError<'tcx>> { + pub fn make_canonicalized_query_response<T>( + &self, + inference_vars: CanonicalVarValues<'tcx>, + answer: T, + ) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution> + where + T: Debug + TypeFoldable<TyCtxt<'tcx>>, + Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>, + { + self.infcx.make_canonicalized_query_response( + inference_vars, + answer, + &mut **self.engine.borrow_mut(), + ) + } +} +impl<'tcx, E> ObligationCtxt<'_, 'tcx, E> +where + E: FromSolverError<'tcx, NextSolverError<'tcx>>, +{ pub fn assumed_wf_types( &self, param_env: ty::ParamEnv<'tcx>, def_id: LocalDefId, - ) -> Result<FxIndexSet<Ty<'tcx>>, Vec<FulfillmentError<'tcx>>> { + ) -> Result<FxIndexSet<Ty<'tcx>>, Vec<E>> { let tcx = self.infcx.tcx; let mut implied_bounds = FxIndexSet::default(); let mut errors = Vec::new(); @@ -281,19 +300,23 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { if errors.is_empty() { Ok(implied_bounds) } else { Err(errors) } } - pub fn make_canonicalized_query_response<T>( + pub fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>( &self, - inference_vars: CanonicalVarValues<'tcx>, - answer: T, - ) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution> - where - T: Debug + TypeFoldable<TyCtxt<'tcx>>, - Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>, - { - self.infcx.make_canonicalized_query_response( - inference_vars, - answer, - &mut **self.engine.borrow_mut(), - ) + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: T, + ) -> Result<T, Vec<E>> { + self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut()) + } + + pub fn structurally_normalize( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: Ty<'tcx>, + ) -> Result<Ty<'tcx>, Vec<E>> { + self.infcx + .at(cause, param_env) + .structurally_normalize(value, &mut **self.engine.borrow_mut()) } } 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 3ee33295176..c7da85bd1cc 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -28,7 +28,7 @@ use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk}; use rustc_macros::extension; use rustc_middle::hir::map; use rustc_middle::traits::IsConstable; -use rustc_middle::ty::error::TypeError::{self, Sorts}; +use rustc_middle::ty::error::TypeError; use rustc_middle::ty::print::PrintPolyTraitRefExt; use rustc_middle::ty::{ self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, GenericArgs, @@ -1112,7 +1112,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { { Some(( DefIdOrName::DefId(def_id), - pred.kind().rebind(proj.term.ty().unwrap()), + pred.kind().rebind(proj.term.expect_type()), pred.kind().rebind(args.as_slice()), )) } else { @@ -1129,7 +1129,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { { Some(( DefIdOrName::Name("trait object"), - pred.rebind(proj.term.ty().unwrap()), + pred.rebind(proj.term.expect_type()), pred.rebind(args.as_slice()), )) } else { @@ -1157,7 +1157,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { { Some(( name, - pred.kind().rebind(proj.term.ty().unwrap()), + pred.kind().rebind(proj.term.expect_type()), pred.kind().rebind(args.as_slice()), )) } else { @@ -3840,9 +3840,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }) } else if let Some(where_pred) = where_pred.as_projection_clause() && let Some(failed_pred) = failed_pred.as_projection_clause() - && let Some(found) = failed_pred.skip_binder().term.ty() + && let Some(found) = failed_pred.skip_binder().term.as_type() { - type_diffs = vec![Sorts(ty::error::ExpectedFound { + type_diffs = vec![TypeError::Sorts(ty::error::ExpectedFound { expected: where_pred .skip_binder() .projection_term @@ -3985,7 +3985,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { continue; }; for diff in type_diffs { - let Sorts(expected_found) = diff else { + let TypeError::Sorts(expected_found) = diff else { continue; }; if tcx.is_diagnostic_item(sym::IteratorItem, *def_id) @@ -4165,7 +4165,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { }; if primary_spans.is_empty() || type_diffs.iter().any(|diff| { - let Sorts(expected_found) = diff else { + let TypeError::Sorts(expected_found) = diff else { return false; }; self.can_eq(param_env, expected_found.found, ty) @@ -4198,7 +4198,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let assoc = with_forced_trimmed_paths!(self.tcx.def_path_str(assoc)); if !self.can_eq(param_env, ty, *prev_ty) { if type_diffs.iter().any(|diff| { - let Sorts(expected_found) = diff else { + let TypeError::Sorts(expected_found) = diff else { return false; }; self.can_eq(param_env, expected_found.found, ty) @@ -4248,7 +4248,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let ocx = ObligationCtxt::new(self.infcx); let mut assocs_in_this_method = Vec::with_capacity(type_diffs.len()); for diff in type_diffs { - let Sorts(expected_found) = diff else { + let TypeError::Sorts(expected_found) = diff else { continue; }; let ty::Alias(ty::Projection, proj) = expected_found.expected.kind() else { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index da611b748da..46b13788186 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 @@ -414,7 +414,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => { let trait_predicate = bound_predicate.rebind(trait_predicate); let trait_predicate = self.resolve_vars_if_possible(trait_predicate); - let trait_predicate = self.apply_do_not_recommend(trait_predicate, &mut obligation); // Let's use the root obligation as the main message, when we care about the // most general case ("X doesn't implement Pattern<'_>") over the case that @@ -877,56 +876,25 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) => { - // Errors for `ConstEvaluatable` predicates show up as - // `SelectionError::ConstEvalFailure`, - // not `Unimplemented`. + // Errors for `ConstEvaluatable` predicates show up as + // `SelectionError::ConstEvalFailure`, + // not `Unimplemented`. + ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) + // Errors for `ConstEquate` predicates show up as + // `SelectionError::ConstEvalFailure`, + // not `Unimplemented`. + | ty::PredicateKind::ConstEquate { .. } + // Ambiguous predicates should never error + | ty::PredicateKind::Ambiguous + | ty::PredicateKind::NormalizesTo { .. } + | ty::PredicateKind::AliasRelate { .. } + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType { .. }) => { span_bug!( span, - "const-evaluatable requirement gave wrong error: `{:?}`", + "Unexpected `Predicate` for `SelectionError`: `{:?}`", obligation ) } - - ty::PredicateKind::ConstEquate(..) => { - // Errors for `ConstEquate` predicates show up as - // `SelectionError::ConstEvalFailure`, - // not `Unimplemented`. - span_bug!( - span, - "const-equate requirement gave wrong error: `{:?}`", - obligation - ) - } - - ty::PredicateKind::Ambiguous => span_bug!(span, "ambiguous"), - - ty::PredicateKind::NormalizesTo(..) => span_bug!( - span, - "NormalizesTo predicate should never be the predicate cause of a SelectionError" - ), - - ty::PredicateKind::AliasRelate(..) => span_bug!( - span, - "AliasRelate predicate should never be the predicate cause of a SelectionError" - ), - - ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { - let mut diag = self.dcx().struct_span_err( - span, - format!("the constant `{ct}` is not of type `{ty}`"), - ); - self.note_type_err( - &mut diag, - &obligation.cause, - None, - None, - TypeError::Sorts(ty::error::ExpectedFound::new(true, ty, ct.ty())), - false, - false, - ); - diag - } } } @@ -989,6 +957,24 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { Overflow(_) => { bug!("overflow should be handled before the `report_selection_error` path"); } + + SelectionError::ConstArgHasWrongType { ct, ct_ty, expected_ty } => { + let mut diag = self.dcx().struct_span_err( + span, + format!("the constant `{ct}` is not of type `{expected_ty}`"), + ); + + self.note_type_err( + &mut diag, + &obligation.cause, + None, + None, + TypeError::Sorts(ty::error::ExpectedFound::new(true, expected_ty, ct_ty)), + false, + false, + ); + diag + } }; self.note_obligation_cause(&mut err, &obligation); @@ -996,12 +982,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { err.emit() } - fn apply_do_not_recommend( - &self, - mut trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, - obligation: &'_ mut PredicateObligation<'tcx>, - ) -> ty::Binder<'tcx, ty::TraitPredicate<'tcx>> { + fn apply_do_not_recommend(&self, obligation: &mut PredicateObligation<'tcx>) -> bool { let mut base_cause = obligation.cause.code().clone(); + let mut applied_do_not_recommend = false; loop { if let ObligationCauseCode::ImplDerived(ref c) = base_cause { if self.tcx.has_attrs_with_path( @@ -1011,7 +994,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let code = (*c.derived.parent_code).clone(); obligation.cause.map_code(|_| code); obligation.predicate = c.derived.parent_trait_pred.upcast(self.tcx); - trait_predicate = c.derived.parent_trait_pred.clone(); + applied_do_not_recommend = true; } } if let Some((parent_cause, _parent_pred)) = base_cause.parent() { @@ -1021,7 +1004,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - trait_predicate + applied_do_not_recommend } fn emit_specialized_closure_kind_error( @@ -1521,6 +1504,20 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { #[instrument(skip(self), level = "debug")] fn report_fulfillment_error(&self, error: &FulfillmentError<'tcx>) -> ErrorGuaranteed { + let mut error = FulfillmentError { + obligation: error.obligation.clone(), + code: error.code.clone(), + root_obligation: error.root_obligation.clone(), + }; + if matches!( + error.code, + FulfillmentErrorCode::Select(crate::traits::SelectionError::Unimplemented) + | FulfillmentErrorCode::Project(_) + ) && self.apply_do_not_recommend(&mut error.obligation) + { + error.code = FulfillmentErrorCode::Select(SelectionError::Unimplemented); + } + match error.code { FulfillmentErrorCode::Select(ref selection_error) => self.report_selection_error( error.obligation.clone(), diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index e1afc2a3529..bce5c7101cc 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -6,7 +6,7 @@ use rustc_data_structures::obligation_forest::ProcessResult; use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome}; use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; use rustc_infer::infer::DefineOpaqueTypes; -use rustc_infer::traits::ProjectionCacheKey; +use rustc_infer::traits::{FromSolverError, ProjectionCacheKey}; use rustc_infer::traits::{PolyTraitObligation, SelectionError, TraitEngine}; use rustc_middle::bug; use rustc_middle::mir::interpret::ErrorHandled; @@ -16,13 +16,13 @@ use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, Binder, Const, TypeVisitableExt}; use std::marker::PhantomData; -use super::const_evaluatable; use super::project::{self, ProjectAndUnifyResult}; use super::select::SelectionContext; use super::wf; use super::EvaluationResult; use super::PredicateObligation; use super::Unimplemented; +use super::{const_evaluatable, ScrubbedTraitError}; use super::{FulfillmentError, FulfillmentErrorCode}; use crate::traits::project::PolyProjectionObligation; @@ -50,7 +50,7 @@ impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { /// along. Once all type inference constraints have been generated, the /// method `select_all_or_error` can be used to report any remaining /// ambiguous cases as errors. -pub struct FulfillmentContext<'tcx> { +pub struct FulfillmentContext<'tcx, E: 'tcx> { /// A list of all obligations that have been registered with this /// fulfillment context. predicates: ObligationForest<PendingPredicateObligation<'tcx>>, @@ -60,6 +60,8 @@ pub struct FulfillmentContext<'tcx> { /// gets rolled back. Because of this we explicitly check that we only /// use the context in exactly this snapshot. usable_in_snapshot: usize, + + _errors: PhantomData<E>, } #[derive(Clone, Debug)] @@ -76,9 +78,12 @@ pub struct PendingPredicateObligation<'tcx> { #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(PendingPredicateObligation<'_>, 72); -impl<'tcx> FulfillmentContext<'tcx> { +impl<'tcx, E> FulfillmentContext<'tcx, E> +where + E: FromSolverError<'tcx, OldSolverError<'tcx>>, +{ /// Creates a new fulfillment context. - pub(super) fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentContext<'tcx> { + pub(super) fn new(infcx: &InferCtxt<'tcx>) -> FulfillmentContext<'tcx, E> { assert!( !infcx.next_trait_solver(), "old trait solver fulfillment context created when \ @@ -87,13 +92,15 @@ impl<'tcx> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), usable_in_snapshot: infcx.num_open_snapshots(), + _errors: PhantomData, } } /// Attempts to select obligations using `selcx`. - fn select(&mut self, selcx: SelectionContext<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> { + fn select(&mut self, selcx: SelectionContext<'_, 'tcx>) -> Vec<E> { let span = debug_span!("select", obligation_forest_size = ?self.predicates.len()); let _enter = span.enter(); + let infcx = selcx.infcx; // Process pending obligations. let outcome: Outcome<_, _> = @@ -102,8 +109,11 @@ impl<'tcx> FulfillmentContext<'tcx> { // FIXME: if we kept the original cache key, we could mark projection // obligations as complete for the projection cache here. - let errors: Vec<FulfillmentError<'tcx>> = - outcome.errors.into_iter().map(to_fulfillment_error).collect(); + let errors: Vec<E> = outcome + .errors + .into_iter() + .map(|err| E::from_solver_error(infcx, OldSolverError(err))) + .collect(); debug!( "select({} predicates remaining, {} errors) done", @@ -115,7 +125,10 @@ impl<'tcx> FulfillmentContext<'tcx> { } } -impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { +impl<'tcx, E> TraitEngine<'tcx, E> for FulfillmentContext<'tcx, E> +where + E: FromSolverError<'tcx, OldSolverError<'tcx>>, +{ #[inline] fn register_predicate_obligation( &mut self, @@ -134,18 +147,15 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); } - fn collect_remaining_errors( - &mut self, - _infcx: &InferCtxt<'tcx>, - ) -> Vec<FulfillmentError<'tcx>> { + fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> { self.predicates .to_errors(FulfillmentErrorCode::Ambiguity { overflow: None }) .into_iter() - .map(to_fulfillment_error) + .map(|err| E::from_solver_error(infcx, OldSolverError(err))) .collect() } - fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> { + fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> { let selcx = SelectionContext::new(infcx); self.select(selcx) } @@ -411,7 +421,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) { + if !self.selcx.tcx().is_object_safe(trait_def_id) { ProcessResult::Error(FulfillmentErrorCode::Select(Unimplemented)) } else { ProcessResult::Changed(vec![]) @@ -429,37 +439,50 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { // This is because this is not ever a useful obligation to report // as the cause of an overflow. ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { - // FIXME(BoxyUwU): Really we should not be calling `ct.ty()` for any variant - // other than `ConstKind::Value`. Unfortunately this would require looking in the - // env for any `ConstArgHasType` assumptions for parameters and placeholders. I - // don't really want to implement this in the old solver so I haven't. - // - // We do still stall on infer vars though as otherwise a goal like: - // `ConstArgHasType(?x: usize, usize)` can succeed even though it might later - // get unified with some const that is not of type `usize`. - let ct = self.selcx.infcx.shallow_resolve_const(ct); - match ct.kind() { - ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { + let ct = infcx.shallow_resolve_const(ct); + let ct_ty = match ct.kind() { + ty::ConstKind::Infer(var) => { + let var = match var { + ty::InferConst::Var(vid) => TyOrConstInferVar::Const(vid), + ty::InferConst::EffectVar(vid) => TyOrConstInferVar::Effect(vid), + ty::InferConst::Fresh(_) => { + bug!("encountered fresh const in fulfill") + } + }; pending_obligation.stalled_on.clear(); - pending_obligation.stalled_on.extend([TyOrConstInferVar::Const(vid)]); - ProcessResult::Unchanged + pending_obligation.stalled_on.extend([var]); + return ProcessResult::Unchanged; } ty::ConstKind::Error(_) => return ProcessResult::Changed(vec![]), - _ => { - match self.selcx.infcx.at(&obligation.cause, obligation.param_env).eq( - // Only really excercised by generic_const_exprs - DefineOpaqueTypes::Yes, - ct.ty(), - ty, - ) { - Ok(inf_ok) => { - ProcessResult::Changed(mk_pending(inf_ok.into_obligations())) - } - Err(_) => ProcessResult::Error(FulfillmentErrorCode::Select( - SelectionError::Unimplemented, - )), - } + ty::ConstKind::Value(ty, _) => ty, + ty::ConstKind::Unevaluated(uv) => { + infcx.tcx.type_of(uv.def).instantiate(infcx.tcx, uv.args) } + // FIXME(generic_const_exprs): we should construct an alias like + // `<lhs_ty as Add<rhs_ty>>::Output` when this is an `Expr` representing + // `lhs + rhs`. + ty::ConstKind::Expr(_) => { + return ProcessResult::Changed(mk_pending(vec![])); + } + ty::ConstKind::Placeholder(_) => { + bug!("placeholder const {:?} in old solver", ct) + } + ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct), + ty::ConstKind::Param(param_ct) => { + param_ct.find_ty_from_env(obligation.param_env) + } + }; + + match infcx.at(&obligation.cause, obligation.param_env).eq( + // Only really excercised by generic_const_exprs + DefineOpaqueTypes::Yes, + ct_ty, + ty, + ) { + Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())), + Err(_) => ProcessResult::Error(FulfillmentErrorCode::Select( + SelectionError::ConstArgHasWrongType { ct, ct_ty, expected_ty: ty }, + )), } } @@ -623,7 +646,6 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { match self.selcx.infcx.try_const_eval_resolve( obligation.param_env, unevaluated, - c.ty(), obligation.cause.span, ) { Ok(val) => Ok(val), @@ -840,13 +862,31 @@ fn args_infer_vars<'a, 'tcx>( .filter_map(TyOrConstInferVar::maybe_from_generic_arg) } -fn to_fulfillment_error<'tcx>( - error: Error<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>>, -) -> FulfillmentError<'tcx> { - let mut iter = error.backtrace.into_iter(); - let obligation = iter.next().unwrap().obligation; - // The root obligation is the last item in the backtrace - if there's only - // one item, then it's the same as the main obligation - let root_obligation = iter.next_back().map_or_else(|| obligation.clone(), |e| e.obligation); - FulfillmentError::new(obligation, error.error, root_obligation) +#[derive(Debug)] +pub struct OldSolverError<'tcx>( + Error<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>>, +); + +impl<'tcx> FromSolverError<'tcx, OldSolverError<'tcx>> for FulfillmentError<'tcx> { + fn from_solver_error(_infcx: &InferCtxt<'tcx>, error: OldSolverError<'tcx>) -> Self { + let mut iter = error.0.backtrace.into_iter(); + let obligation = iter.next().unwrap().obligation; + // The root obligation is the last item in the backtrace - if there's only + // one item, then it's the same as the main obligation + let root_obligation = iter.next_back().map_or_else(|| obligation.clone(), |e| e.obligation); + FulfillmentError::new(obligation, error.0.error, root_obligation) + } +} + +impl<'tcx> FromSolverError<'tcx, OldSolverError<'tcx>> for ScrubbedTraitError<'tcx> { + fn from_solver_error(_infcx: &InferCtxt<'tcx>, error: OldSolverError<'tcx>) -> Self { + match error.0.error { + FulfillmentErrorCode::Select(_) + | FulfillmentErrorCode::Project(_) + | FulfillmentErrorCode::Subtype(_, _) + | FulfillmentErrorCode::ConstEquate(_, _) => ScrubbedTraitError::TrueError, + FulfillmentErrorCode::Ambiguity { overflow: _ } => ScrubbedTraitError::Ambiguity, + FulfillmentErrorCode::Cycle(cycle) => ScrubbedTraitError::Cycle(cycle), + } + } } diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index a1094d98276..baec2268629 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -1,13 +1,13 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. use crate::regions::InferCtxtRegionExt; -use crate::traits::{self, ObligationCause}; +use crate::traits::{self, FulfillmentError, ObligationCause}; use hir::LangItem; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; +use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; -use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError}; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt}; use super::outlives_bounds::InferCtxtExt; @@ -137,7 +137,7 @@ pub fn all_fields_implement_trait<'tcx>( for field in &variant.fields { // Do this per-field to get better error messages. let infcx = tcx.infer_ctxt().build(); - let ocx = traits::ObligationCtxt::new(&infcx); + let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); let unnormalized_ty = field.ty(tcx, args); if unnormalized_ty.references_error() { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 786ab091e91..eae2f9d1792 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -32,6 +32,7 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_errors::ErrorGuaranteed; use rustc_middle::query::Providers; use rustc_middle::span_bug; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, Upcast}; @@ -46,7 +47,7 @@ pub use self::coherence::{add_placeholder_note, orphan_check_trait_ref, overlapp pub use self::coherence::{InCrate, IsFirstInputType, UncoveredTyParams}; pub use self::coherence::{OrphanCheckErr, OrphanCheckMode, OverlapResult}; pub use self::engine::{ObligationCtxt, TraitEngineExt}; -pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation}; +pub use self::fulfill::{FulfillmentContext, OldSolverError, PendingPredicateObligation}; pub use self::normalize::NormalizeExt; pub use self::object_safety::hir_ty_lowering_object_safety_violations; pub use self::object_safety::is_vtable_safe_method; @@ -70,6 +71,80 @@ pub use self::util::{with_replaced_escaping_bound_vars, BoundVarReplacer, Placeh pub use rustc_infer::traits::*; +pub struct FulfillmentError<'tcx> { + pub obligation: PredicateObligation<'tcx>, + pub code: FulfillmentErrorCode<'tcx>, + /// Diagnostics only: the 'root' obligation which resulted in + /// the failure to process `obligation`. This is the obligation + /// that was initially passed to `register_predicate_obligation` + pub root_obligation: PredicateObligation<'tcx>, +} + +impl<'tcx> FulfillmentError<'tcx> { + pub fn new( + obligation: PredicateObligation<'tcx>, + code: FulfillmentErrorCode<'tcx>, + root_obligation: PredicateObligation<'tcx>, + ) -> FulfillmentError<'tcx> { + FulfillmentError { obligation, code, root_obligation } + } + + pub fn is_true_error(&self) -> bool { + match self.code { + FulfillmentErrorCode::Select(_) + | FulfillmentErrorCode::Project(_) + | FulfillmentErrorCode::Subtype(_, _) + | FulfillmentErrorCode::ConstEquate(_, _) => true, + FulfillmentErrorCode::Cycle(_) | FulfillmentErrorCode::Ambiguity { overflow: _ } => { + false + } + } + } +} + +impl<'tcx> Debug for FulfillmentError<'tcx> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code) + } +} + +#[derive(Clone)] +pub enum FulfillmentErrorCode<'tcx> { + /// Inherently impossible to fulfill; this trait is implemented if and only + /// if it is already implemented. + Cycle(Vec<PredicateObligation<'tcx>>), + Select(SelectionError<'tcx>), + Project(MismatchedProjectionTypes<'tcx>), + Subtype(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate + ConstEquate(ExpectedFound<ty::Const<'tcx>>, 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 + /// emitting a fatal error instead. + overflow: Option<bool>, + }, +} + +impl<'tcx> Debug for FulfillmentErrorCode<'tcx> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + FulfillmentErrorCode::Select(ref e) => write!(f, "{e:?}"), + FulfillmentErrorCode::Project(ref e) => write!(f, "{e:?}"), + FulfillmentErrorCode::Subtype(ref a, ref b) => { + write!(f, "CodeSubtypeError({a:?}, {b:?})") + } + FulfillmentErrorCode::ConstEquate(ref a, ref b) => { + write!(f, "CodeConstEquateError({a:?}, {b:?})") + } + FulfillmentErrorCode::Ambiguity { overflow: None } => write!(f, "Ambiguity"), + FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => { + write!(f, "Overflow({suggest_increasing_limit})") + } + FulfillmentErrorCode::Cycle(ref cycle) => write!(f, "Cycle({cycle:?})"), + } + } +} + /// Whether to skip the leak check, as part of a future compatibility warning step. /// /// The "default" for skip-leak-check corresponds to the current @@ -284,7 +359,7 @@ pub fn normalize_param_env_or_error<'tcx>( // `ty::Const::normalize` can only work with properly preserved binders. if c.has_escaping_bound_vars() { - return ty::Const::new_misc_error(self.0, c.ty()); + return ty::Const::new_misc_error(self.0); } // While it is pretty sus to be evaluating things with an empty param env, it // should actually be okay since without `feature(generic_const_exprs)` the only @@ -407,7 +482,7 @@ pub fn fully_normalize<'tcx, T>( where T: TypeFoldable<TyCtxt<'tcx>>, { - let ocx = ObligationCtxt::new(infcx); + let ocx = ObligationCtxt::new_with_diagnostics(infcx); debug!(?value); let normalized_value = ocx.normalize(&cause, param_env, value); debug!(?normalized_value); @@ -548,6 +623,7 @@ pub fn provide(providers: &mut Providers) { *providers = Providers { specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, + specialization_enabled_in: specialize::specialization_enabled_in, instantiate_and_check_impossible_predicates, is_impossible_associated_item, ..*providers diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index d10aee2d4e2..e7ab0b7791c 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -3,11 +3,13 @@ use super::error_reporting::OverflowCause; use super::error_reporting::TypeErrCtxtExt; use super::SelectionContext; use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer}; +use crate::solve::NextSolverError; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::at::At; use rustc_infer::infer::InferOk; +use rustc_infer::traits::FromSolverError; use rustc_infer::traits::PredicateObligation; -use rustc_infer::traits::{FulfillmentError, Normalized, Obligation, TraitEngine}; +use rustc_infer::traits::{Normalized, Obligation, TraitEngine}; use rustc_macros::extension; use rustc_middle::traits::{ObligationCause, ObligationCauseCode, Reveal}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFolder}; @@ -44,11 +46,15 @@ impl<'tcx> At<'_, 'tcx> { /// existing fulfillment context in the old solver. Once we also eagerly prove goals with /// the old solver or have removed the old solver, remove `traits::fully_normalize` and /// rename this function to `At::fully_normalize`. - fn deeply_normalize<T: TypeFoldable<TyCtxt<'tcx>>>( + fn deeply_normalize<T, E>( self, value: T, - fulfill_cx: &mut dyn TraitEngine<'tcx>, - ) -> Result<T, Vec<FulfillmentError<'tcx>>> { + fulfill_cx: &mut dyn TraitEngine<'tcx, E>, + ) -> Result<T, Vec<E>> + where + T: TypeFoldable<TyCtxt<'tcx>>, + E: FromSolverError<'tcx, NextSolverError<'tcx>>, + { if self.infcx.next_trait_solver() { crate::solve::deeply_normalize(self, value) } else { @@ -253,7 +259,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx obligations.len = ?self.obligations.len(), "AssocTypeNormalizer: normalized type" ); - normalized_ty.ty().unwrap() + normalized_ty.expect_type() } ty::Projection => { @@ -283,7 +289,7 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx ) .ok() .flatten() - .map(|term| term.ty().unwrap()) + .map(|term| term.expect_type()) .map(|normalized_ty| { PlaceholderReplacer::replace_placeholders( infcx, diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 0f32b6ef9e3..08355ef55c4 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -13,7 +13,7 @@ use super::elaborate; use crate::infer::TyCtxtInferExt; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{self, Obligation, ObligationCause}; -use rustc_errors::{FatalError, MultiSpan}; +use rustc_errors::FatalError; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::query::Providers; @@ -23,7 +23,6 @@ use rustc_middle::ty::{ }; use rustc_middle::ty::{GenericArg, GenericArgs}; use rustc_middle::ty::{TypeVisitableExt, Upcast}; -use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::abi::Abi; @@ -65,45 +64,14 @@ fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &'_ [Object ) } -fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { - let violations = tcx.object_safety_violations(trait_def_id); - - if violations.is_empty() { - return true; - } - - // If the trait contains any other violations, then let the error reporting path - // report it instead of emitting a warning here. - if violations.iter().all(|violation| { - matches!( - violation, - ObjectSafetyViolation::Method(_, MethodViolationCode::WhereClauseReferencesSelf, _) - ) - }) { - for violation in violations { - if let ObjectSafetyViolation::Method( - _, - MethodViolationCode::WhereClauseReferencesSelf, - span, - ) = violation - { - lint_object_unsafe_trait(tcx, *span, trait_def_id, violation); - } - } - return true; - } - - false +fn is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { + tcx.object_safety_violations(trait_def_id).is_empty() } /// We say a method is *vtable safe* if it can be invoked on a trait /// object. Note that object-safe traits can have some /// non-vtable-safe methods, so long as they require `Self: Sized` or /// otherwise ensure that they cannot be used when `Self = Trait`. -/// -/// [`MethodViolationCode::WhereClauseReferencesSelf`] is considered object safe due to backwards -/// compatibility, see <https://github.com/rust-lang/rust/issues/51443> and -/// [`WHERE_CLAUSES_OBJECT_SAFETY`]. pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::AssocItem) -> bool { debug_assert!(tcx.generics_of(trait_def_id).has_self); debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method); @@ -112,9 +80,7 @@ pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::A return false; } - virtual_call_violations_for_method(tcx, trait_def_id, method) - .iter() - .all(|v| matches!(v, MethodViolationCode::WhereClauseReferencesSelf)) + virtual_call_violations_for_method(tcx, trait_def_id, method).is_empty() } fn object_safety_violations_for_trait( @@ -163,47 +129,6 @@ fn object_safety_violations_for_trait( violations } -/// Lint object-unsafe trait. -fn lint_object_unsafe_trait( - tcx: TyCtxt<'_>, - span: Span, - trait_def_id: DefId, - violation: &ObjectSafetyViolation, -) { - // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id. - // It's also hard to get a use site span, so we use the method definition span. - tcx.node_span_lint(WHERE_CLAUSES_OBJECT_SAFETY, hir::CRATE_HIR_ID, span, |err| { - err.primary_message(format!( - "the trait `{}` cannot be made into an object", - tcx.def_path_str(trait_def_id) - )); - let node = tcx.hir().get_if_local(trait_def_id); - let mut spans = MultiSpan::from_span(span); - if let Some(hir::Node::Item(item)) = node { - spans.push_span_label(item.ident.span, "this trait cannot be made into an object..."); - spans.push_span_label(span, format!("...because {}", violation.error_msg())); - } else { - spans.push_span_label( - span, - format!( - "the trait cannot be made into an object because {}", - violation.error_msg() - ), - ); - }; - err.span_note( - spans, - "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 \ - <https://doc.rust-lang.org/reference/items/traits.html#object-safety>", - ); - if node.is_some() { - // Only provide the help if its a local trait, otherwise it's not - violation.solution().add_to(err); - } - }); -} - fn sized_trait_bound_spans<'tcx>( tcx: TyCtxt<'tcx>, bounds: hir::GenericBounds<'tcx>, @@ -929,7 +854,7 @@ pub fn contains_illegal_impl_trait_in_trait<'tcx>( pub fn provide(providers: &mut Providers) { *providers = Providers { object_safety_violations, - check_is_object_safe, + is_object_safe, generics_require_sized_self, ..*providers }; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 501d9c9266e..2c9cb79664b 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -523,16 +523,9 @@ fn normalize_to_error<'a, 'tcx>( | ty::AliasTermKind::InherentTy | ty::AliasTermKind::OpaqueTy | ty::AliasTermKind::WeakTy => selcx.infcx.next_ty_var(cause.span).into(), - ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => selcx - .infcx - .next_const_var( - selcx - .tcx() - .type_of(projection_term.def_id) - .instantiate(selcx.tcx(), projection_term.args), - cause.span, - ) - .into(), + ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { + selcx.infcx.next_const_var(cause.span).into() + } }; let trait_obligation = Obligation { cause, @@ -744,8 +737,6 @@ fn project<'cx, 'tcx>( obligation.predicate.def_id, obligation.predicate.args, ), - tcx.type_of(obligation.predicate.def_id) - .instantiate(tcx, obligation.predicate.args), ) .into(), kind => { @@ -2071,15 +2062,14 @@ fn confirm_impl_candidate<'cx, 'tcx>( // * `args` ends up as `[u32, S]` let args = obligation.predicate.args.rebase_onto(tcx, trait_def_id, args); let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_ty.defining_node); - let ty = tcx.type_of(assoc_ty.item.def_id); let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst); let term: ty::EarlyBinder<'tcx, ty::Term<'tcx>> = if is_const { let did = assoc_ty.item.def_id; let identity_args = crate::traits::GenericArgs::identity_for_item(tcx, did); let uv = ty::UnevaluatedConst::new(did, identity_args); - ty.map_bound(|ty| ty::Const::new_unevaluated(tcx, uv, ty).into()) + ty::EarlyBinder::bind(ty::Const::new_unevaluated(tcx, uv).into()) } else { - ty.map_bound(|ty| ty.into()) + tcx.type_of(assoc_ty.item.def_id).map_bound(|ty| ty.into()) }; if !tcx.check_args_compatible(assoc_ty.item.def_id, args) { let err = Ty::new_error_with_message( diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 1b5ffeebc01..e170d7cae93 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -8,11 +8,11 @@ use crate::infer::{InferCtxt, InferOk}; use crate::traits::error_reporting::OverflowCause; use crate::traits::error_reporting::TypeErrCtxtExt; use crate::traits::normalize::needs_normalization; -use crate::traits::{BoundVarReplacer, PlaceholderReplacer}; +use crate::traits::Normalized; +use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError}; use crate::traits::{ObligationCause, PredicateObligation, Reveal}; use rustc_data_structures::sso::SsoHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_infer::traits::Normalized; use rustc_macros::extension; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt}; @@ -76,7 +76,9 @@ impl<'cx, 'tcx> At<'cx, 'tcx> { }; if self.infcx.next_trait_solver() { - match crate::solve::deeply_normalize_with_skipped_universes(self, value, universes) { + match crate::solve::deeply_normalize_with_skipped_universes::<_, ScrubbedTraitError<'tcx>>( + self, value, universes, + ) { Ok(value) => return Ok(Normalized { value, obligations: vec![] }), Err(_errors) => { return Err(NoSolution); diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 00cc77e71e7..b38841db923 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -1,4 +1,3 @@ -use crate::solve; use crate::traits::query::NoSolution; use crate::traits::wf; use crate::traits::ObligationCtxt; @@ -262,11 +261,9 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>( let mut ty_a = ocx.infcx.resolve_vars_if_possible(ty_a); // Need to manually normalize in the new solver as `wf::obligations` does not. if ocx.infcx.next_trait_solver() { - ty_a = solve::deeply_normalize( - ocx.infcx.at(&ObligationCause::dummy(), param_env), - ty_a, - ) - .map_err(|_errs| NoSolution)?; + ty_a = ocx + .deeply_normalize(&ObligationCause::dummy(), param_env, ty_a) + .map_err(|_| NoSolution)?; } let mut components = smallvec![]; push_outlives_components(tcx, ty_a, &mut components); diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index d513a5d2996..6db5fa0e4e5 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -870,7 +870,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let Some(principal) = data.principal() { if !self.infcx.tcx.features().object_safe_for_dispatch { principal.with_self_ty(self.tcx(), self_ty) - } else if self.tcx().check_is_object_safe(principal.def_id()) { + } else if self.tcx().is_object_safe(principal.def_id()) { principal.with_self_ty(self.tcx(), self_ty) } else { return; @@ -921,6 +921,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { param_env: ty::ParamEnv<'tcx>, cause: &ObligationCause<'tcx>, ) -> Option<ty::PolyExistentialTraitRef<'tcx>> { + // Don't drop any candidates in intercrate mode, as it's incomplete. + // (Not that it matters, since `Unsize` is not a stable trait.) + if self.infcx.intercrate { + return None; + } + let tcx = self.tcx(); if tcx.features().trait_upcasting { return None; @@ -946,7 +952,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // since we don't actually use them. &mut vec![], ) - .ty() + .as_type() .unwrap(); if let ty::Dynamic(data, ..) = ty.kind() { data.principal() } else { None } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index c684f087d32..749081006f3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -665,9 +665,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { tcx, ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1), - tcx.type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"), ) .into() } @@ -1222,7 +1219,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `T` -> `Trait` (_, &ty::Dynamic(data, r, ty::Dyn)) => { let mut object_dids = data.auto_traits().chain(data.principal_def_id()); - if let Some(did) = object_dids.find(|did| !tcx.check_is_object_safe(*did)) { + if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) { return Err(TraitNotObjectSafe(did)); } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index dcb0875639f..4a935f4a64a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -32,6 +32,8 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_infer::infer::relate::MatchAgainstFreshVars; +use rustc_infer::infer::relate::TypeRelation; use rustc_infer::infer::BoundRegionConversionTime; use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType; use rustc_infer::infer::DefineOpaqueTypes; @@ -40,10 +42,9 @@ use rustc_middle::bug; use rustc_middle::dep_graph::dep_kinds; 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::error::TypeErrorToStringExt; use rustc_middle::ty::print::PrintTraitRefExt as _; -use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, PolyProjectionPredicate, Upcast}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; @@ -798,7 +799,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::PredicateKind::ObjectSafe(trait_def_id) => { - if self.tcx().check_is_object_safe(trait_def_id) { + if self.tcx().is_object_safe(trait_def_id) { Ok(EvaluatedToOk) } else { Ok(EvaluatedToErr) @@ -947,7 +948,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match self.infcx.try_const_eval_resolve( obligation.param_env, unevaluated, - c.ty(), obligation.cause.span, ) { Ok(val) => Ok(val), @@ -995,21 +995,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { - // FIXME(BoxyUwU): Really we should not be calling `ct.ty()` for any variant - // other than `ConstKind::Value`. Unfortunately this would require looking in the - // env for any `ConstArgHasType` assumptions for parameters and placeholders. I - // don't really want to implement this in the old solver so I haven't. - // - // We do still stall on infer vars though as otherwise a goal like: - // `ConstArgHasType(?x: usize, usize)` can succeed even though it might later - // get unified with some const that is not of type `usize`. let ct = self.infcx.shallow_resolve_const(ct); let ct_ty = match ct.kind() { - ty::ConstKind::Infer(ty::InferConst::Var(_)) => { + ty::ConstKind::Infer(_) => { return Ok(EvaluatedToAmbig); } ty::ConstKind::Error(_) => return Ok(EvaluatedToOk), - _ => ct.ty(), + ty::ConstKind::Value(ty, _) => ty, + ty::ConstKind::Unevaluated(uv) => { + self.tcx().type_of(uv.def).instantiate(self.tcx(), uv.args) + } + // FIXME(generic_const_exprs): See comment in `fulfill.rs` + ty::ConstKind::Expr(_) => return Ok(EvaluatedToOk), + ty::ConstKind::Placeholder(_) => { + bug!("placeholder const {:?} in old solver", ct) + } + ty::ConstKind::Bound(_, _) => bug!("escaping bound vars in {:?}", ct), + ty::ConstKind::Param(param_ct) => { + param_ct.find_ty_from_env(obligation.param_env) + } }; match self.infcx.at(&obligation.cause, obligation.param_env).eq( diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index c2727ae6bfd..c9bb0d330e1 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -24,6 +24,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{codes::*, Diag, EmissionGuarantee}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::bug; +use rustc_middle::query::LocalCrate; use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK; @@ -136,6 +137,10 @@ pub fn translate_args_with_cause<'tcx>( source_args.rebase_onto(infcx.tcx, source_impl, target_args) } +pub(super) fn specialization_enabled_in(tcx: TyCtxt<'_>, _: LocalCrate) -> bool { + tcx.features().specialization || tcx.features().min_specialization +} + /// Is `impl1` a specialization of `impl2`? /// /// Specialization is determined by the sets of types to which the impls apply; @@ -143,31 +148,18 @@ pub fn translate_args_with_cause<'tcx>( /// to. #[instrument(skip(tcx), level = "debug")] pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, DefId)) -> bool { - // The feature gate should prevent introducing new specializations, but not - // taking advantage of upstream ones. - // If specialization is enabled for this crate then no extra checks are needed. - // If it's not, and either of the `impl`s is local to this crate, then this definitely - // isn't specializing - unless specialization is enabled for the `impl` span, - // e.g. if it comes from an `allow_internal_unstable` macro - let features = tcx.features(); - let specialization_enabled = features.specialization || features.min_specialization; - if !specialization_enabled { - if impl1_def_id.is_local() { - let span = tcx.def_span(impl1_def_id); - if !span.allows_unstable(sym::specialization) - && !span.allows_unstable(sym::min_specialization) - { - return false; - } - } - - if impl2_def_id.is_local() { - let span = tcx.def_span(impl2_def_id); - if !span.allows_unstable(sym::specialization) - && !span.allows_unstable(sym::min_specialization) - { - return false; - } + // We check that the specializing impl comes from a crate that has specialization enabled, + // or if the specializing impl is marked with `allow_internal_unstable`. + // + // We don't really care if the specialized impl (the parent) is in a crate that has + // specialization enabled, since it's not being specialized, and it's already been checked + // for coherence. + if !tcx.specialization_enabled_in(impl1_def_id.krate) { + let span = tcx.def_span(impl1_def_id); + if !span.allows_unstable(sym::specialization) + && !span.allows_unstable(sym::min_specialization) + { + return false; } } diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index 96a06e0c169..9d657ade86b 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -1,5 +1,5 @@ use rustc_infer::infer::at::At; -use rustc_infer::traits::{FulfillmentError, TraitEngine}; +use rustc_infer::traits::TraitEngine; use rustc_macros::extension; use rustc_middle::ty::{self, Ty}; @@ -7,11 +7,11 @@ use crate::traits::{NormalizeExt, Obligation}; #[extension(pub trait StructurallyNormalizeExt<'tcx>)] impl<'tcx> At<'_, 'tcx> { - fn structurally_normalize( + fn structurally_normalize<E: 'tcx>( &self, ty: Ty<'tcx>, - fulfill_cx: &mut dyn TraitEngine<'tcx>, - ) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> { + fulfill_cx: &mut dyn TraitEngine<'tcx, E>, + ) -> Result<Ty<'tcx>, Vec<E>> { assert!(!ty.is_ty_var(), "should have resolved vars before calling"); if self.infcx.next_trait_solver() { diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 5d5a22e189c..960c27b636e 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -483,7 +483,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for BoundVarReplacer<'_, 'tcx> { let universe = self.universe_for(debruijn); let p = ty::PlaceholderConst { universe, bound: bound_const }; self.mapped_consts.insert(p, bound_const); - ty::Const::new_placeholder(self.infcx.tcx, p, ct.ty()) + ty::Const::new_placeholder(self.infcx.tcx, p) } _ => ct.super_fold_with(self), } @@ -626,7 +626,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> { let db = ty::DebruijnIndex::from_usize( self.universe_indices.len() - index + self.current_index.as_usize() - 1, ); - ty::Const::new_bound(self.infcx.tcx, db, *replace_var, ct.ty()) + ty::Const::new_bound(self.infcx.tcx, db, *replace_var) } None => { if ct.has_infer() { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index f4189ff0902..066755f7b3e 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -286,7 +286,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( // implemented, but rather from a "second order" obligation, where an associated // type has a projection coming from another associated type. // See `tests/ui/traits/assoc-type-in-superbad.rs` for an example. - if let Some(term_ty) = proj.term.ty() + if let Some(term_ty) = proj.term.as_type() && let Some(impl_item_span) = ty_to_impl_span(term_ty) { cause.span = impl_item_span; diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index b96b1b67a74..c73ececd1d1 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -4,13 +4,13 @@ // general routines. use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::FulfillmentErrorCode; use rustc_middle::bug; use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::{ - ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext, Unimplemented, + ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext, + Unimplemented, }; use tracing::debug; @@ -50,6 +50,7 @@ pub fn codegen_select_candidate<'tcx>( // Currently, we use a fulfillment context to completely resolve // all nested obligations. This is because they can inform the // inference of the impl's type parameters. + // FIXME(-Znext-solver): Doesn't need diagnostics if new solver. let ocx = ObligationCtxt::new(&infcx); let impl_source = selection.map(|obligation| { ocx.register_obligation(obligation); @@ -64,7 +65,7 @@ pub fn codegen_select_candidate<'tcx>( // Cycle errors are the only post-monomorphization errors possible; emit them now so // `rustc_ty_utils::resolve_associated_item` doesn't return `None` post-monomorphization. for err in errors { - if let FulfillmentErrorCode::Cycle(cycle) = err.code { + if let ScrubbedTraitError::Cycle(cycle) = err { infcx.err_ctxt().report_overflow_obligation_cycle(&cycle); } } diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index fee13078250..0430e0bb70e 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -7,9 +7,7 @@ use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::query::{ normalize::NormalizationResult, CanonicalAliasGoal, NoSolution, }; -use rustc_trait_selection::traits::{ - self, FulfillmentErrorCode, ObligationCause, SelectionContext, -}; +use rustc_trait_selection::traits::{self, ObligationCause, ScrubbedTraitError, SelectionContext}; use tracing::debug; pub(crate) fn provide(p: &mut Providers) { @@ -49,7 +47,7 @@ fn normalize_canonicalized_projection_ty<'tcx>( // that impl vars are constrained by the signature, for example). if !tcx.sess.opts.actually_rustdoc { for error in &errors { - if let FulfillmentErrorCode::Cycle(cycle) = &error.code { + if let ScrubbedTraitError::Cycle(cycle) = &error { ocx.infcx.err_ctxt().report_overflow_obligation_cycle(cycle); } } @@ -60,7 +58,7 @@ fn normalize_canonicalized_projection_ty<'tcx>( // FIXME(associated_const_equality): All users of normalize_canonicalized_projection_ty // expected a type, but there is the possibility it could've been a const now. // Maybe change it to a Term later? - Ok(NormalizationResult { normalized_ty: answer.ty().unwrap() }) + Ok(NormalizationResult { normalized_ty: answer.expect_type() }) }, ) } diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 604b68d2cd4..eae1a9dfaa2 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -420,7 +420,7 @@ pub(crate) mod rustc { fn from_tag(tag: ScalarInt, tcx: TyCtxt<'tcx>) -> Self { use rustc_target::abi::Endian; let size = tag.size(); - let bits = tag.assert_bits(size); + let bits = tag.to_bits(size); let bytes: [u8; 16]; let bytes = match tcx.data_layout.endian { Endian::Little => { diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 8d7d81d8f73..ffebf7b0721 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -135,7 +135,7 @@ mod rustc { use rustc_middle::ty::ScalarInt; use rustc_span::symbol::sym; - let Ok(cv) = c.eval(tcx, param_env, DUMMY_SP) else { + let Ok((ty, cv)) = c.eval(tcx, param_env, DUMMY_SP) else { return Some(Self { alignment: true, lifetimes: true, @@ -144,7 +144,7 @@ mod rustc { }); }; - let adt_def = c.ty().ty_adt_def()?; + let adt_def = ty.ty_adt_def()?; assert_eq!( tcx.require_lang_item(LangItem::TransmuteOpts, None), diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index e9112d232cb..58f812fc7cf 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -23,7 +23,7 @@ fn destructure_const<'tcx>( tcx: TyCtxt<'tcx>, const_: ty::Const<'tcx>, ) -> ty::DestructuredConst<'tcx> { - let ty::ConstKind::Value(valtree) = const_.kind() else { + let ty::ConstKind::Value(ct_ty, valtree) = const_.kind() else { bug!("cannot destructure constant {:?}", const_) }; @@ -32,7 +32,7 @@ fn destructure_const<'tcx>( _ => bug!("cannot destructure constant {:?}", const_), }; - let (fields, variant) = match const_.ty().kind() { + let (fields, variant) = match ct_ty.kind() { ty::Array(inner_ty, _) | ty::Slice(inner_ty) => { // construct the consts for the elements of the array/slice let field_consts = branches @@ -47,7 +47,7 @@ fn destructure_const<'tcx>( ty::Adt(def, args) => { let (variant_idx, branches) = if def.is_enum() { let (head, rest) = branches.split_first().unwrap(); - (VariantIdx::from_u32(head.unwrap_leaf().try_to_u32().unwrap()), rest) + (VariantIdx::from_u32(head.unwrap_leaf().to_u32()), rest) } else { (FIRST_VARIANT, branches) }; @@ -121,7 +121,7 @@ fn recurse_build<'tcx>( let sp = node.span; match tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) { Ok(c) => c, - Err(LitToConstError::Reported(guar)) => ty::Const::new_error(tcx, guar, node.ty), + Err(LitToConstError::Reported(guar)) => ty::Const::new_error(tcx, guar), Err(LitToConstError::TypeError) => { bug!("encountered type error in lit_to_const") } @@ -137,28 +137,31 @@ fn recurse_build<'tcx>( } &ExprKind::NamedConst { def_id, args, user_ty: _ } => { let uneval = ty::UnevaluatedConst::new(def_id, args); - ty::Const::new_unevaluated(tcx, uneval, node.ty) + ty::Const::new_unevaluated(tcx, uneval) } - ExprKind::ConstParam { param, .. } => ty::Const::new_param(tcx, *param, node.ty), + ExprKind::ConstParam { param, .. } => ty::Const::new_param(tcx, *param), ExprKind::Call { fun, args, .. } => { + let fun_ty = body.exprs[*fun].ty; let fun = recurse_build(tcx, body, *fun, root_span)?; let mut new_args = Vec::<ty::Const<'tcx>>::with_capacity(args.len()); for &id in args.iter() { new_args.push(recurse_build(tcx, body, id, root_span)?); } - let new_args = tcx.mk_const_list(&new_args); - ty::Const::new_expr(tcx, Expr::FunctionCall(fun, new_args), node.ty) + ty::Const::new_expr(tcx, Expr::new_call(tcx, fun_ty, fun, new_args)) } &ExprKind::Binary { op, lhs, rhs } if check_binop(op) => { + let lhs_ty = body.exprs[lhs].ty; let lhs = recurse_build(tcx, body, lhs, root_span)?; + let rhs_ty = body.exprs[rhs].ty; let rhs = recurse_build(tcx, body, rhs, root_span)?; - ty::Const::new_expr(tcx, Expr::Binop(op, lhs, rhs), node.ty) + ty::Const::new_expr(tcx, Expr::new_binop(tcx, op, lhs_ty, rhs_ty, lhs, rhs)) } &ExprKind::Unary { op, arg } if check_unop(op) => { + let arg_ty = body.exprs[arg].ty; let arg = recurse_build(tcx, body, arg, root_span)?; - ty::Const::new_expr(tcx, Expr::UnOp(op, arg), node.ty) + ty::Const::new_expr(tcx, Expr::new_unop(tcx, op, arg_ty, arg)) } // This is necessary so that the following compiles: // @@ -178,12 +181,14 @@ fn recurse_build<'tcx>( // "coercion cast" i.e. using a coercion or is a no-op. // This is important so that `N as usize as usize` doesn't unify with `N as usize`. (untested) &ExprKind::Use { source } => { - let arg = recurse_build(tcx, body, source, root_span)?; - ty::Const::new_expr(tcx, Expr::Cast(CastKind::Use, arg, node.ty), node.ty) + let value_ty = body.exprs[source].ty; + let value = recurse_build(tcx, body, source, root_span)?; + ty::Const::new_expr(tcx, Expr::new_cast(tcx, CastKind::Use, value_ty, value, node.ty)) } &ExprKind::Cast { source } => { - let arg = recurse_build(tcx, body, source, root_span)?; - ty::Const::new_expr(tcx, Expr::Cast(CastKind::As, arg, node.ty), node.ty) + let value_ty = body.exprs[source].ty; + let value = recurse_build(tcx, body, source, root_span)?; + ty::Const::new_expr(tcx, Expr::new_cast(tcx, CastKind::As, value_ty, value, node.ty)) } ExprKind::Borrow { arg, .. } => { let arg_node = &body.exprs[*arg]; diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 1c30f03c693..61ae36265ec 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -115,8 +115,8 @@ impl<I: Interner> CanonicalVarInfo<I> { CanonicalVarKind::PlaceholderTy(_) => false, CanonicalVarKind::Region(_) => true, CanonicalVarKind::PlaceholderRegion(..) => false, - CanonicalVarKind::Const(..) => true, - CanonicalVarKind::PlaceholderConst(_, _) => false, + CanonicalVarKind::Const(_) => true, + CanonicalVarKind::PlaceholderConst(_) => false, CanonicalVarKind::Effect => true, } } @@ -126,8 +126,8 @@ impl<I: Interner> CanonicalVarInfo<I> { CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => true, CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) - | CanonicalVarKind::Const(_, _) - | CanonicalVarKind::PlaceholderConst(_, _) + | CanonicalVarKind::Const(_) + | CanonicalVarKind::PlaceholderConst(_) | CanonicalVarKind::Effect => false, } } @@ -136,12 +136,12 @@ impl<I: Interner> CanonicalVarInfo<I> { match self.kind { CanonicalVarKind::Ty(_) | CanonicalVarKind::Region(_) - | CanonicalVarKind::Const(_, _) + | CanonicalVarKind::Const(_) | CanonicalVarKind::Effect => panic!("expected placeholder: {self:?}"), CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.var().as_usize(), CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.var().as_usize(), - CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.var().as_usize(), + CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.var().as_usize(), } } } @@ -169,13 +169,13 @@ pub enum CanonicalVarKind<I: Interner> { PlaceholderRegion(I::PlaceholderRegion), /// Some kind of const inference variable. - Const(UniverseIndex, I::Ty), + Const(UniverseIndex), /// Effect variable `'?E`. Effect, /// A "placeholder" that represents "any const". - PlaceholderConst(I::PlaceholderConst, I::Ty), + PlaceholderConst(I::PlaceholderConst), } impl<I: Interner> PartialEq for CanonicalVarKind<I> { @@ -185,10 +185,8 @@ impl<I: Interner> PartialEq for CanonicalVarKind<I> { (Self::PlaceholderTy(l0), Self::PlaceholderTy(r0)) => l0 == r0, (Self::Region(l0), Self::Region(r0)) => l0 == r0, (Self::PlaceholderRegion(l0), Self::PlaceholderRegion(r0)) => l0 == r0, - (Self::Const(l0, l1), Self::Const(r0, r1)) => l0 == r0 && l1 == r1, - (Self::PlaceholderConst(l0, l1), Self::PlaceholderConst(r0, r1)) => { - l0 == r0 && l1 == r1 - } + (Self::Const(l0), Self::Const(r0)) => l0 == r0, + (Self::PlaceholderConst(l0), Self::PlaceholderConst(r0)) => l0 == r0, _ => std::mem::discriminant(self) == std::mem::discriminant(other), } } @@ -199,10 +197,10 @@ impl<I: Interner> CanonicalVarKind<I> { match self { CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) => ui, CanonicalVarKind::Region(ui) => ui, - CanonicalVarKind::Const(ui, _) => ui, + CanonicalVarKind::Const(ui) => ui, CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe(), CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe(), - CanonicalVarKind::PlaceholderConst(placeholder, _) => placeholder.universe(), + CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe(), CanonicalVarKind::Ty(CanonicalTyVarKind::Float | CanonicalTyVarKind::Int) => { UniverseIndex::ROOT } @@ -220,7 +218,7 @@ impl<I: Interner> CanonicalVarKind<I> { CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)) } CanonicalVarKind::Region(_) => CanonicalVarKind::Region(ui), - CanonicalVarKind::Const(_, ty) => CanonicalVarKind::Const(ui, ty), + CanonicalVarKind::Const(_) => CanonicalVarKind::Const(ui), CanonicalVarKind::PlaceholderTy(placeholder) => { CanonicalVarKind::PlaceholderTy(placeholder.with_updated_universe(ui)) @@ -228,8 +226,8 @@ impl<I: Interner> CanonicalVarKind<I> { CanonicalVarKind::PlaceholderRegion(placeholder) => { CanonicalVarKind::PlaceholderRegion(placeholder.with_updated_universe(ui)) } - CanonicalVarKind::PlaceholderConst(placeholder, ty) => { - CanonicalVarKind::PlaceholderConst(placeholder.with_updated_universe(ui), ty) + CanonicalVarKind::PlaceholderConst(placeholder) => { + CanonicalVarKind::PlaceholderConst(placeholder.with_updated_universe(ui)) } CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) | CanonicalVarKind::Effect => { @@ -345,21 +343,14 @@ impl<I: Interner> CanonicalVarValues<I> { Region::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i)) .into() } - CanonicalVarKind::Effect => Const::new_anon_bound( - tcx, - ty::INNERMOST, - ty::BoundVar::from_usize(i), - Ty::new_bool(tcx), - ) - .into(), - CanonicalVarKind::Const(_, ty) - | CanonicalVarKind::PlaceholderConst(_, ty) => Const::new_anon_bound( - tcx, - ty::INNERMOST, - ty::BoundVar::from_usize(i), - ty, - ) - .into(), + CanonicalVarKind::Effect => { + Const::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i)) + .into() + } + CanonicalVarKind::Const(_) | CanonicalVarKind::PlaceholderConst(_) => { + Const::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i)) + .into() + } } }, )), diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 7076df2893f..84d48e14c24 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -32,7 +32,7 @@ pub enum ConstKind<I: Interner> { Unevaluated(ty::UnevaluatedConst<I>), /// Used to hold computed value. - Value(I::ValueConst), + Value(I::Ty, I::ValueConst), /// A placeholder for a const which could not be computed; this is /// propagated to avoid useless error messages. @@ -51,7 +51,7 @@ impl<I: Interner> PartialEq for ConstKind<I> { (Bound(l0, l1), Bound(r0, r1)) => l0 == r0 && l1 == r1, (Placeholder(l0), Placeholder(r0)) => l0 == r0, (Unevaluated(l0), Unevaluated(r0)) => l0 == r0, - (Value(l0), Value(r0)) => l0 == r0, + (Value(l0, l1), Value(r0, r1)) => l0 == r0 && l1 == r1, (Error(l0), Error(r0)) => l0 == r0, (Expr(l0), Expr(r0)) => l0 == r0, _ => false, @@ -80,7 +80,7 @@ impl<I: Interner> DebugWithInfcx<I> for ConstKind<I> { Unevaluated(uv) => { write!(f, "{:?}", &this.wrap(uv)) } - Value(valtree) => write!(f, "{valtree:?}"), + Value(ty, valtree) => write!(f, "({valtree:?}: {:?})", &this.wrap(ty)), Error(_) => write!(f, "{{const error}}"), Expr(expr) => write!(f, "{:?}", &this.wrap(expr)), } diff --git a/compiler/rustc_type_ir/src/debug.rs b/compiler/rustc_type_ir/src/debug.rs index 4e8be1ee4c2..c206f3ccdb5 100644 --- a/compiler/rustc_type_ir/src/debug.rs +++ b/compiler/rustc_type_ir/src/debug.rs @@ -38,11 +38,11 @@ impl<I: Interner> InferCtxtLike for NoInfcx<I> { panic!("cannot resolve {vid:?}") } - fn opportunistic_resolve_ct_var(&self, vid: ConstVid, _: I::Ty) -> I::Const { + fn opportunistic_resolve_ct_var(&self, vid: ConstVid) -> I::Const { panic!("cannot resolve {vid:?}") } - fn opportunistic_resolve_effect_var(&self, vid: EffectVid, _: I::Ty) -> I::Const { + fn opportunistic_resolve_effect_var(&self, vid: EffectVid) -> I::Const { panic!("cannot resolve {vid:?}") } diff --git a/compiler/rustc_type_ir/src/error.rs b/compiler/rustc_type_ir/src/error.rs new file mode 100644 index 00000000000..27623ea9cac --- /dev/null +++ b/compiler/rustc_type_ir/src/error.rs @@ -0,0 +1,106 @@ +use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; + +use crate::solve::NoSolution; +use crate::{self as ty, Interner}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(TypeFoldable_Generic, TypeVisitable_Generic)] +pub struct ExpectedFound<T> { + pub expected: T, + pub found: T, +} + +impl<T> ExpectedFound<T> { + pub fn new(a_is_expected: bool, a: T, b: T) -> Self { + if a_is_expected { + ExpectedFound { expected: a, found: b } + } else { + ExpectedFound { expected: b, found: a } + } + } +} + +// Data structures used in type unification +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Copy(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = "") +)] +#[derive(TypeVisitable_Generic)] +#[rustc_pass_by_value] +pub enum TypeError<I: Interner> { + Mismatch, + ConstnessMismatch(ExpectedFound<ty::BoundConstness>), + PolarityMismatch(ExpectedFound<ty::PredicatePolarity>), + SafetyMismatch(ExpectedFound<I::Safety>), + AbiMismatch(ExpectedFound<I::Abi>), + Mutability, + ArgumentMutability(usize), + TupleSize(ExpectedFound<usize>), + FixedArraySize(ExpectedFound<u64>), + ArgCount, + + RegionsDoesNotOutlive(I::Region, I::Region), + RegionsInsufficientlyPolymorphic(I::BoundRegion, I::Region), + RegionsPlaceholderMismatch, + + Sorts(ExpectedFound<I::Ty>), + ArgumentSorts(ExpectedFound<I::Ty>, usize), + Traits(ExpectedFound<I::DefId>), + VariadicMismatch(ExpectedFound<bool>), + + /// Instantiating a type variable with the given type would have + /// created a cycle (because it appears somewhere within that + /// type). + CyclicTy(I::Ty), + CyclicConst(I::Const), + ProjectionMismatched(ExpectedFound<I::DefId>), + ExistentialMismatch(ExpectedFound<I::BoundExistentialPredicates>), + ConstMismatch(ExpectedFound<I::Const>), + + IntrinsicCast, + /// Safe `#[target_feature]` functions are not assignable to safe function pointers. + TargetFeatureCast(I::DefId), +} + +impl<I: Interner> TypeError<I> { + pub fn involves_regions(self) -> bool { + match self { + TypeError::RegionsDoesNotOutlive(_, _) + | TypeError::RegionsInsufficientlyPolymorphic(_, _) + | TypeError::RegionsPlaceholderMismatch => true, + _ => false, + } + } + + pub fn must_include_note(self) -> bool { + use self::TypeError::*; + match self { + CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | ConstnessMismatch(_) + | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_) + | ArgumentSorts(..) | Sorts(_) | VariadicMismatch(_) | TargetFeatureCast(_) => false, + + Mutability + | ArgumentMutability(_) + | TupleSize(_) + | ArgCount + | RegionsDoesNotOutlive(..) + | RegionsInsufficientlyPolymorphic(..) + | RegionsPlaceholderMismatch + | Traits(_) + | ProjectionMismatched(_) + | ExistentialMismatch(_) + | ConstMismatch(_) + | IntrinsicCast => true, + } + } +} + +impl<I: Interner> From<TypeError<I>> for NoSolution { + fn from(_: TypeError<I>) -> NoSolution { + NoSolution + } +} diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index 501311ff72f..ee3e5ce66d0 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -387,7 +387,7 @@ impl<I: Interner> TypeFolder<I> for Shifter<I> { match ct.kind() { ty::ConstKind::Bound(debruijn, bound_ct) if debruijn >= self.current_index => { let debruijn = debruijn.shifted_in(self.amount); - Const::new_bound(self.tcx, debruijn, bound_ct, ct.ty()) + Const::new_bound(self.tcx, debruijn, bound_ct) } _ => ct.super_fold_with(self), } diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs index bb5081fb335..24e10722448 100644 --- a/compiler/rustc_type_ir/src/infcx.rs +++ b/compiler/rustc_type_ir/src/infcx.rs @@ -12,15 +12,10 @@ pub trait InferCtxtLike { fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> <Self::Interner as Interner>::Ty; fn opportunistic_resolve_int_var(&self, vid: IntVid) -> <Self::Interner as Interner>::Ty; fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> <Self::Interner as Interner>::Ty; - fn opportunistic_resolve_ct_var( - &self, - vid: ConstVid, - ty: <Self::Interner as Interner>::Ty, - ) -> <Self::Interner as Interner>::Const; + fn opportunistic_resolve_ct_var(&self, vid: ConstVid) -> <Self::Interner as Interner>::Const; fn opportunistic_resolve_effect_var( &self, vid: EffectVid, - ty: <Self::Interner as Interner>::Ty, ) -> <Self::Interner as Interner>::Const; fn opportunistic_resolve_lt_var(&self, vid: RegionVid) -> <Self::Interner as Interner>::Region; diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index f305ed9b5d7..205a1e5f100 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -7,7 +7,10 @@ use std::fmt::Debug; use std::hash::Hash; use std::ops::Deref; +use rustc_ast_ir::Mutability; + use crate::fold::{TypeFoldable, TypeSuperFoldable}; +use crate::relate::Relate; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty, CollectAndApply, DebugWithInfcx, Interner, UpcastFrom}; @@ -21,6 +24,7 @@ pub trait Ty<I: Interner<Ty = Self>>: + IntoKind<Kind = ty::TyKind<I>> + TypeSuperVisitable<I> + TypeSuperFoldable<I> + + Relate<I> + Flags { fn new_bool(interner: I) -> Self; @@ -35,8 +39,37 @@ pub trait Ty<I: Interner<Ty = Self>>: fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy<I>) -> Self; + fn new_error(interner: I, guar: I::ErrorGuaranteed) -> Self; + + fn new_adt(interner: I, adt_def: I::AdtDef, args: I::GenericArgs) -> Self; + + fn new_foreign(interner: I, def_id: I::DefId) -> Self; + + fn new_dynamic( + interner: I, + preds: I::BoundExistentialPredicates, + region: I::Region, + kind: ty::DynKind, + ) -> Self; + fn new_coroutine(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + fn new_coroutine_closure(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + + fn new_closure(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + + fn new_coroutine_witness(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + + fn new_ptr(interner: I, ty: Self, mutbl: Mutability) -> Self; + + fn new_ref(interner: I, region: I::Region, ty: Self, mutbl: Mutability) -> Self; + + fn new_array_with_const_len(interner: I, ty: Self, len: I::Const) -> Self; + + fn new_slice(interner: I, ty: Self) -> Self; + + fn new_tup(interner: I, tys: &[I::Ty]) -> Self; + fn new_tup_from_iter<It, T>(interner: I, iter: It) -> T::Output where It: Iterator<Item = T>, @@ -49,6 +82,12 @@ pub trait Ty<I: Interner<Ty = Self>>: fn from_closure_kind(interner: I, kind: ty::ClosureKind) -> Self; fn from_coroutine_closure_kind(interner: I, kind: ty::ClosureKind) -> Self; + + fn new_fn_def(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + + fn new_fn_ptr(interner: I, sig: ty::Binder<I, ty::FnSig<I>>) -> Self; + + fn new_pat(interner: I, ty: Self, pat: I::Pat) -> Self; } pub trait Tys<I: Interner<Tys = Self>>: @@ -84,6 +123,7 @@ pub trait Region<I: Interner<Region = Self>>: + IntoKind<Kind = ty::RegionKind<I>> + Flags + TypeVisitable<I> + + Relate<I> { fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundRegion) -> Self; @@ -102,24 +142,22 @@ pub trait Const<I: Interner<Const = Self>>: + IntoKind<Kind = ty::ConstKind<I>> + TypeSuperVisitable<I> + TypeSuperFoldable<I> + + Relate<I> + Flags { - fn new_infer(interner: I, var: ty::InferConst, ty: I::Ty) -> Self; + fn try_to_target_usize(self, interner: I) -> Option<u64>; - fn new_var(interner: I, var: ty::ConstVid, ty: I::Ty) -> Self; + fn new_infer(interner: I, var: ty::InferConst) -> Self; - fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundConst, ty: I::Ty) -> Self; + fn new_var(interner: I, var: ty::ConstVid) -> Self; - fn new_anon_bound( - interner: I, - debruijn: ty::DebruijnIndex, - var: ty::BoundVar, - ty: I::Ty, - ) -> Self; + fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundConst) -> Self; - fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst<I>, ty: I::Ty) -> Self; + fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self; - fn ty(self) -> I::Ty; + fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst<I>) -> Self; + + fn new_expr(interner: I, expr: I::ExprConst) -> Self; } pub trait GenericsOf<I: Interner<GenericsOf = Self>> { @@ -135,13 +173,14 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>: + Deref<Target: Deref<Target = [I::GenericArg]>> + Default + TypeFoldable<I> + + Relate<I> { fn type_at(self, i: usize) -> I::Ty; fn identity_for_item(interner: I, def_id: I::DefId) -> I::GenericArgs; fn extend_with_error( - tcx: I, + interner: I, def_id: I::DefId, original_args: &[I::GenericArg], ) -> I::GenericArgs; @@ -200,3 +239,11 @@ pub trait BoundVarLike<I: Interner> { pub trait ParamLike { fn index(self) -> u32; } + +pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq { + fn def_id(self) -> I::DefId; +} + +pub trait Features<I: Interner>: Copy { + fn generic_const_exprs(self) -> bool; +} diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 6ebb434299b..ad1d2753b28 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -6,6 +6,7 @@ use std::ops::Deref; use crate::fold::TypeFoldable; use crate::inherent::*; use crate::ir_print::IrPrint; +use crate::relate::Relate; use crate::solve::inspect::CanonicalGoalEvaluationStep; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; use crate::{self as ty, DebugWithInfcx}; @@ -25,8 +26,8 @@ pub trait Interner: + IrPrint<ty::CoercePredicate<Self>> + IrPrint<ty::FnSig<Self>> { - type DefId: Copy + Debug + Hash + Eq + TypeVisitable<Self>; - type AdtDef: Copy + Debug + Hash + Eq; + type DefId: Copy + Debug + Hash + Eq + TypeFoldable<Self>; + type AdtDef: AdtDef<Self>; type GenericArgs: GenericArgs<Self>; type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref<Target = [Self::GenericArg]>; @@ -35,8 +36,15 @@ pub trait Interner: + Hash + Eq + IntoKind<Kind = ty::GenericArgKind<Self>> - + TypeVisitable<Self>; - type Term: Copy + Debug + Hash + Eq + IntoKind<Kind = ty::TermKind<Self>> + TypeVisitable<Self>; + + TypeVisitable<Self> + + Relate<Self>; + type Term: Copy + + Debug + + Hash + + Eq + + IntoKind<Kind = ty::TermKind<Self>> + + TypeFoldable<Self> + + Relate<Self>; type BoundVarKinds: Copy + Debug @@ -66,11 +74,11 @@ pub trait Interner: // Things stored inside of tys type ErrorGuaranteed: Copy + Debug + Hash + Eq; - type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Eq; + type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Eq + Relate<Self>; type AllocId: Copy + Debug + Hash + Eq; - type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx<Self>; - type Safety: Safety<Self>; - type Abi: Abi<Self>; + type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx<Self> + Relate<Self>; + type Safety: Safety<Self> + TypeFoldable<Self> + Relate<Self>; + type Abi: Abi<Self> + TypeFoldable<Self> + Relate<Self>; // Kinds of consts type Const: Const<Self>; @@ -78,7 +86,7 @@ pub trait Interner: type ParamConst: Copy + Debug + Hash + Eq + ParamLike; type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>; type ValueConst: Copy + Debug + Hash + Eq; - type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Eq; + type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Eq + Relate<Self>; // Kinds of regions type Region: Region<Self>; @@ -93,11 +101,16 @@ pub trait Interner: type Clause: Clause<Self>; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags; + fn expand_abstract_consts<T: TypeFoldable<Self>>(self, t: T) -> T; + fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars; type GenericsOf: GenericsOf<Self>; fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf; + type VariancesOf: Copy + Debug + Deref<Target = [ty::Variance]>; + fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf; + // FIXME: Remove after uplifting `EarlyBinder` fn type_of(self, def_id: Self::DefId) -> ty::EarlyBinder<Self, Self::Ty>; @@ -112,7 +125,12 @@ pub trait Interner: ) -> (ty::TraitRef<Self>, Self::GenericArgsSlice); fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs; - fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> Self::GenericArgs; + + fn mk_args_from_iter<I, T>(self, args: I) -> T::Output + where + I: Iterator<Item = T>, + T: CollectAndApply<Self::GenericArg, Self::GenericArgs>; + fn check_and_mk_args( self, def_id: Self::DefId, @@ -124,9 +142,17 @@ pub trait Interner: step: CanonicalGoalEvaluationStep<Self>, ) -> Self::CanonicalGoalEvaluationStepRef; + fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output + where + I: Iterator<Item = T>, + T: CollectAndApply<Self::Ty, Self::Tys>; + fn parent(self, def_id: Self::DefId) -> Self::DefId; fn recursion_limit(self) -> usize; + + type Features: Features<Self>; + fn features(self) -> Self::Features; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 217c056d0ba..73716468930 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -21,18 +21,20 @@ use std::hash::Hash; #[cfg(not(feature = "nightly"))] use std::sync::Arc as Lrc; +// These modules are `pub` since they are not glob-imported. #[macro_use] pub mod visit; #[cfg(feature = "nightly")] pub mod codec; +pub mod error; pub mod fold; pub mod inherent; pub mod ir_print; pub mod lift; +pub mod relate; pub mod solve; -pub mod ty_info; -pub mod ty_kind; +// These modules are not `pub` since they are glob-imported. #[macro_use] mod macros; mod binder; @@ -46,6 +48,8 @@ mod interner; mod predicate; mod predicate_kind; mod region_kind; +mod ty_info; +mod ty_kind; mod upcast; pub use binder::*; diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index f2f7b165de5..aae5aeb5fb3 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -48,10 +48,22 @@ TrivialTypeTraversalImpls! { u32, u64, String, - crate::DebruijnIndex, crate::AliasRelationDirection, + crate::AliasTyKind, + crate::BoundConstness, + crate::DebruijnIndex, + crate::FloatTy, + crate::InferTy, + crate::IntVarValue, + crate::PredicatePolarity, + crate::RegionVid, + crate::solve::BuiltinImplSource, + crate::solve::Certainty, + crate::solve::GoalSource, + crate::solve::MaybeCause, + crate::solve::NoSolution, crate::UniverseIndex, - rustc_ast_ir::Mutability, + crate::Variance, rustc_ast_ir::Movability, - crate::PredicatePolarity, + rustc_ast_ir::Mutability, } diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index e7039583c91..63a4c2e9d1f 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -567,7 +567,6 @@ impl<I: Interner> AliasTerm<I> { I::Const::new_unevaluated( interner, ty::UnevaluatedConst::new(self.def_id, self.args), - interner.type_of(self.def_id).instantiate(interner, &self.args), ) .into() } @@ -794,3 +793,36 @@ pub struct CoercePredicate<I: Interner> { pub a: I::Ty, pub b: I::Ty, } + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext, TyEncodable, TyDecodable))] +pub enum BoundConstness { + /// `Type: Trait` + NotConst, + /// `Type: const Trait` + Const, + /// `Type: ~const Trait` + /// + /// Requires resolving to const only when we are in a const context. + ConstIfConst, +} + +impl BoundConstness { + pub fn as_str(self) -> &'static str { + match self { + Self::NotConst => "", + Self::Const => "const", + Self::ConstIfConst => "~const", + } + } +} + +impl fmt::Display for BoundConstness { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::NotConst => f.write_str("normal"), + Self::Const => f.write_str("const"), + Self::ConstIfConst => f.write_str("~const"), + } + } +} diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs new file mode 100644 index 00000000000..cae1d13020d --- /dev/null +++ b/compiler/rustc_type_ir/src/relate.rs @@ -0,0 +1,666 @@ +use std::iter; + +use rustc_ast_ir::Mutability; +use rustc_type_ir::error::{ExpectedFound, TypeError}; +use rustc_type_ir::fold::TypeFoldable; +use rustc_type_ir::inherent::*; +use rustc_type_ir::{self as ty, Interner}; +use tracing::{debug, instrument}; + +pub type RelateResult<I, T> = Result<T, TypeError<I>>; + +/// Extra information about why we ended up with a particular variance. +/// This is only used to add more information to error messages, and +/// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo` +/// may lead to confusing notes in error messages, it will never cause +/// a miscompilation or unsoundness. +/// +/// When in doubt, use `VarianceDiagInfo::default()` +#[derive(derivative::Derivative)] +#[derivative( + Copy(bound = ""), + Clone(bound = ""), + Debug(bound = ""), + Default(bound = ""), + PartialEq(bound = ""), + Eq(bound = "") +)] +pub enum VarianceDiagInfo<I: Interner> { + /// No additional information - this is the default. + /// We will not add any additional information to error messages. + #[derivative(Default)] + None, + /// We switched our variance because a generic argument occurs inside + /// the invariant generic argument of another type. + Invariant { + /// The generic type containing the generic parameter + /// that changes the variance (e.g. `*mut T`, `MyStruct<T>`) + ty: I::Ty, + /// The index of the generic parameter being used + /// (e.g. `0` for `*mut T`, `1` for `MyStruct<'CovariantParam, 'InvariantParam>`) + param_index: u32, + }, +} + +impl<I: Interner> VarianceDiagInfo<I> { + /// Mirrors `Variance::xform` - used to 'combine' the existing + /// and new `VarianceDiagInfo`s when our variance changes. + pub fn xform(self, other: VarianceDiagInfo<I>) -> VarianceDiagInfo<I> { + // For now, just use the first `VarianceDiagInfo::Invariant` that we see + match self { + VarianceDiagInfo::None => other, + VarianceDiagInfo::Invariant { .. } => self, + } + } +} + +pub trait TypeRelation<I: Interner>: Sized { + fn tcx(&self) -> I; + + /// Returns a static string we can use for printouts. + fn tag(&self) -> &'static str; + + /// Generic relation routine suitable for most anything. + fn relate<T: Relate<I>>(&mut self, a: T, b: T) -> RelateResult<I, T> { + Relate::relate(self, a, b) + } + + /// Relate the two args for the given item. The default + /// is to look up the variance for the item and proceed + /// accordingly. + fn relate_item_args( + &mut self, + item_def_id: I::DefId, + a_arg: I::GenericArgs, + b_arg: I::GenericArgs, + ) -> RelateResult<I, I::GenericArgs> { + debug!( + "relate_item_args(item_def_id={:?}, a_arg={:?}, b_arg={:?})", + item_def_id, a_arg, b_arg + ); + + let tcx = self.tcx(); + let opt_variances = tcx.variances_of(item_def_id); + relate_args_with_variances(self, item_def_id, &opt_variances, a_arg, b_arg, true) + } + + /// Switch variance for the purpose of relating `a` and `b`. + fn relate_with_variance<T: Relate<I>>( + &mut self, + variance: ty::Variance, + info: VarianceDiagInfo<I>, + a: T, + b: T, + ) -> RelateResult<I, T>; + + // Overridable relations. You shouldn't typically call these + // directly, instead call `relate()`, which in turn calls + // these. This is both more uniform but also allows us to add + // additional hooks for other types in the future if needed + // without making older code, which called `relate`, obsolete. + + fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult<I, I::Ty>; + + fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult<I, I::Region>; + + fn consts(&mut self, a: I::Const, b: I::Const) -> RelateResult<I, I::Const>; + + fn binders<T>( + &mut self, + a: ty::Binder<I, T>, + b: ty::Binder<I, T>, + ) -> RelateResult<I, ty::Binder<I, T>> + where + T: Relate<I>; +} + +pub trait Relate<I: Interner>: TypeFoldable<I> + PartialEq + Copy { + fn relate<R: TypeRelation<I>>(relation: &mut R, a: Self, b: Self) -> RelateResult<I, Self>; +} + +/////////////////////////////////////////////////////////////////////////// +// Relate impls + +#[inline] +pub fn relate_args_invariantly<I: Interner, R: TypeRelation<I>>( + relation: &mut R, + a_arg: I::GenericArgs, + b_arg: I::GenericArgs, +) -> RelateResult<I, I::GenericArgs> { + relation.tcx().mk_args_from_iter(iter::zip(a_arg, b_arg).map(|(a, b)| { + relation.relate_with_variance(ty::Variance::Invariant, VarianceDiagInfo::default(), a, b) + })) +} + +pub fn relate_args_with_variances<I: Interner, R: TypeRelation<I>>( + relation: &mut R, + ty_def_id: I::DefId, + variances: &[ty::Variance], + a_arg: I::GenericArgs, + b_arg: I::GenericArgs, + fetch_ty_for_diag: bool, +) -> RelateResult<I, I::GenericArgs> { + let tcx = relation.tcx(); + + let mut cached_ty = None; + let params = iter::zip(a_arg, b_arg).enumerate().map(|(i, (a, b))| { + let variance = variances[i]; + let variance_info = if variance == ty::Variance::Invariant && fetch_ty_for_diag { + let ty = + *cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).instantiate(tcx, &a_arg)); + VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() } + } else { + VarianceDiagInfo::default() + }; + relation.relate_with_variance(variance, variance_info, a, b) + }); + + tcx.mk_args_from_iter(params) +} + +impl<I: Interner> Relate<I> for ty::FnSig<I> { + fn relate<R: TypeRelation<I>>( + relation: &mut R, + a: ty::FnSig<I>, + b: ty::FnSig<I>, + ) -> RelateResult<I, ty::FnSig<I>> { + let tcx = relation.tcx(); + + if a.c_variadic != b.c_variadic { + return Err(TypeError::VariadicMismatch({ + let a = a.c_variadic; + let b = b.c_variadic; + ExpectedFound::new(true, a, b) + })); + } + let safety = relation.relate(a.safety, b.safety)?; + let abi = relation.relate(a.abi, b.abi)?; + + let a_inputs = a.inputs(); + let b_inputs = b.inputs(); + + if a_inputs.len() != b_inputs.len() { + return Err(TypeError::ArgCount); + } + + let inputs_and_output = iter::zip(a_inputs.iter(), b_inputs.iter()) + .map(|(&a, &b)| ((a, b), false)) + .chain(iter::once(((a.output(), b.output()), true))) + .map(|((a, b), is_output)| { + if is_output { + relation.relate(a, b) + } else { + relation.relate_with_variance( + ty::Variance::Contravariant, + VarianceDiagInfo::default(), + a, + b, + ) + } + }) + .enumerate() + .map(|(i, r)| match r { + Err(TypeError::Sorts(exp_found) | TypeError::ArgumentSorts(exp_found, _)) => { + Err(TypeError::ArgumentSorts(exp_found, i)) + } + Err(TypeError::Mutability | TypeError::ArgumentMutability(_)) => { + Err(TypeError::ArgumentMutability(i)) + } + r => r, + }); + Ok(ty::FnSig { + inputs_and_output: tcx.mk_type_list_from_iter(inputs_and_output)?, + c_variadic: a.c_variadic, + safety, + abi, + }) + } +} + +impl<I: Interner> Relate<I> for ty::BoundConstness { + fn relate<R: TypeRelation<I>>( + _relation: &mut R, + a: ty::BoundConstness, + b: ty::BoundConstness, + ) -> RelateResult<I, ty::BoundConstness> { + if a != b { + Err(TypeError::ConstnessMismatch(ExpectedFound::new(true, a, b))) + } else { + Ok(a) + } + } +} + +impl<I: Interner> Relate<I> for ty::AliasTy<I> { + fn relate<R: TypeRelation<I>>( + relation: &mut R, + a: ty::AliasTy<I>, + b: ty::AliasTy<I>, + ) -> RelateResult<I, ty::AliasTy<I>> { + if a.def_id != b.def_id { + Err(TypeError::ProjectionMismatched({ + let a = a.def_id; + let b = b.def_id; + ExpectedFound::new(true, a, b) + })) + } else { + let args = match a.kind(relation.tcx()) { + ty::Opaque => relate_args_with_variances( + relation, + a.def_id, + &relation.tcx().variances_of(a.def_id), + a.args, + b.args, + false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle + )?, + ty::Projection | ty::Weak | ty::Inherent => { + relate_args_invariantly(relation, a.args, b.args)? + } + }; + Ok(ty::AliasTy::new(relation.tcx(), a.def_id, args)) + } + } +} + +impl<I: Interner> Relate<I> for ty::AliasTerm<I> { + fn relate<R: TypeRelation<I>>( + relation: &mut R, + a: ty::AliasTerm<I>, + b: ty::AliasTerm<I>, + ) -> RelateResult<I, ty::AliasTerm<I>> { + if a.def_id != b.def_id { + Err(TypeError::ProjectionMismatched({ + let a = a.def_id; + let b = b.def_id; + ExpectedFound::new(true, a, b) + })) + } else { + let args = match a.kind(relation.tcx()) { + ty::AliasTermKind::OpaqueTy => relate_args_with_variances( + relation, + a.def_id, + &relation.tcx().variances_of(a.def_id), + a.args, + b.args, + false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle + )?, + ty::AliasTermKind::ProjectionTy + | ty::AliasTermKind::WeakTy + | ty::AliasTermKind::InherentTy + | ty::AliasTermKind::UnevaluatedConst + | ty::AliasTermKind::ProjectionConst => { + relate_args_invariantly(relation, a.args, b.args)? + } + }; + Ok(ty::AliasTerm::new(relation.tcx(), a.def_id, args)) + } + } +} + +impl<I: Interner> Relate<I> for ty::ExistentialProjection<I> { + fn relate<R: TypeRelation<I>>( + relation: &mut R, + a: ty::ExistentialProjection<I>, + b: ty::ExistentialProjection<I>, + ) -> RelateResult<I, ty::ExistentialProjection<I>> { + if a.def_id != b.def_id { + Err(TypeError::ProjectionMismatched({ + let a = a.def_id; + let b = b.def_id; + ExpectedFound::new(true, a, b) + })) + } else { + let term = relation.relate_with_variance( + ty::Variance::Invariant, + VarianceDiagInfo::default(), + a.term, + b.term, + )?; + let args = relation.relate_with_variance( + ty::Variance::Invariant, + VarianceDiagInfo::default(), + a.args, + b.args, + )?; + Ok(ty::ExistentialProjection { def_id: a.def_id, args, term }) + } + } +} + +impl<I: Interner> Relate<I> for ty::TraitRef<I> { + fn relate<R: TypeRelation<I>>( + relation: &mut R, + a: ty::TraitRef<I>, + b: ty::TraitRef<I>, + ) -> RelateResult<I, ty::TraitRef<I>> { + // Different traits cannot be related. + if a.def_id != b.def_id { + Err(TypeError::Traits({ + let a = a.def_id; + let b = b.def_id; + ExpectedFound::new(true, a, b) + })) + } else { + let args = relate_args_invariantly(relation, a.args, b.args)?; + Ok(ty::TraitRef::new(relation.tcx(), a.def_id, args)) + } + } +} + +impl<I: Interner> Relate<I> for ty::ExistentialTraitRef<I> { + fn relate<R: TypeRelation<I>>( + relation: &mut R, + a: ty::ExistentialTraitRef<I>, + b: ty::ExistentialTraitRef<I>, + ) -> RelateResult<I, ty::ExistentialTraitRef<I>> { + // Different traits cannot be related. + if a.def_id != b.def_id { + Err(TypeError::Traits({ + let a = a.def_id; + let b = b.def_id; + ExpectedFound::new(true, a, b) + })) + } else { + let args = relate_args_invariantly(relation, a.args, b.args)?; + Ok(ty::ExistentialTraitRef { def_id: a.def_id, args }) + } + } +} + +/// Relates `a` and `b` structurally, calling the relation for all nested values. +/// Any semantic equality, e.g. of projections, and inference variables have to be +/// handled by the caller. +#[instrument(level = "trace", skip(relation), ret)] +pub fn structurally_relate_tys<I: Interner, R: TypeRelation<I>>( + relation: &mut R, + a: I::Ty, + b: I::Ty, +) -> RelateResult<I, I::Ty> { + let tcx = relation.tcx(); + match (a.kind(), b.kind()) { + (ty::Infer(_), _) | (_, ty::Infer(_)) => { + // The caller should handle these cases! + panic!("var types encountered in structurally_relate_tys") + } + + (ty::Bound(..), _) | (_, ty::Bound(..)) => { + panic!("bound types encountered in structurally_relate_tys") + } + + (ty::Error(guar), _) | (_, ty::Error(guar)) => Ok(Ty::new_error(tcx, guar)), + + (ty::Never, _) + | (ty::Char, _) + | (ty::Bool, _) + | (ty::Int(_), _) + | (ty::Uint(_), _) + | (ty::Float(_), _) + | (ty::Str, _) + if a == b => + { + Ok(a) + } + + (ty::Param(a_p), ty::Param(b_p)) if a_p.index() == b_p.index() => { + // FIXME: Put this back + //debug_assert_eq!(a_p.name(), b_p.name(), "param types with same index differ in name"); + Ok(a) + } + + (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a), + + (ty::Adt(a_def, a_args), ty::Adt(b_def, b_args)) if a_def == b_def => { + let args = relation.relate_item_args(a_def.def_id(), a_args, b_args)?; + Ok(Ty::new_adt(tcx, a_def, args)) + } + + (ty::Foreign(a_id), ty::Foreign(b_id)) if a_id == b_id => Ok(Ty::new_foreign(tcx, a_id)), + + (ty::Dynamic(a_obj, a_region, a_repr), ty::Dynamic(b_obj, b_region, b_repr)) + if a_repr == b_repr => + { + Ok(Ty::new_dynamic( + tcx, + relation.relate(a_obj, b_obj)?, + relation.relate(a_region, b_region)?, + a_repr, + )) + } + + (ty::Coroutine(a_id, a_args), ty::Coroutine(b_id, b_args)) if a_id == b_id => { + // All Coroutine types with the same id represent + // the (anonymous) type of the same coroutine expression. So + // all of their regions should be equated. + let args = relate_args_invariantly(relation, a_args, b_args)?; + Ok(Ty::new_coroutine(tcx, a_id, args)) + } + + (ty::CoroutineWitness(a_id, a_args), ty::CoroutineWitness(b_id, b_args)) + if a_id == b_id => + { + // All CoroutineWitness types with the same id represent + // the (anonymous) type of the same coroutine expression. So + // all of their regions should be equated. + let args = relate_args_invariantly(relation, a_args, b_args)?; + Ok(Ty::new_coroutine_witness(tcx, a_id, args)) + } + + (ty::Closure(a_id, a_args), ty::Closure(b_id, b_args)) if a_id == b_id => { + // All Closure types with the same id represent + // the (anonymous) type of the same closure expression. So + // all of their regions should be equated. + let args = relate_args_invariantly(relation, a_args, b_args)?; + Ok(Ty::new_closure(tcx, a_id, args)) + } + + (ty::CoroutineClosure(a_id, a_args), ty::CoroutineClosure(b_id, b_args)) + if a_id == b_id => + { + let args = relate_args_invariantly(relation, a_args, b_args)?; + Ok(Ty::new_coroutine_closure(tcx, a_id, args)) + } + + (ty::RawPtr(a_ty, a_mutbl), ty::RawPtr(b_ty, b_mutbl)) => { + if a_mutbl != b_mutbl { + return Err(TypeError::Mutability); + } + + let (variance, info) = match a_mutbl { + Mutability::Not => (ty::Variance::Covariant, VarianceDiagInfo::None), + Mutability::Mut => { + (ty::Variance::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) + } + }; + + let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?; + + Ok(Ty::new_ptr(tcx, ty, a_mutbl)) + } + + (ty::Ref(a_r, a_ty, a_mutbl), ty::Ref(b_r, b_ty, b_mutbl)) => { + if a_mutbl != b_mutbl { + return Err(TypeError::Mutability); + } + + let (variance, info) = match a_mutbl { + Mutability::Not => (ty::Variance::Covariant, VarianceDiagInfo::None), + Mutability::Mut => { + (ty::Variance::Invariant, VarianceDiagInfo::Invariant { ty: a, param_index: 0 }) + } + }; + + let r = relation.relate(a_r, b_r)?; + let ty = relation.relate_with_variance(variance, info, a_ty, b_ty)?; + + Ok(Ty::new_ref(tcx, r, ty, a_mutbl)) + } + + (ty::Array(a_t, sz_a), ty::Array(b_t, sz_b)) => { + let t = relation.relate(a_t, b_t)?; + match relation.relate(sz_a, sz_b) { + Ok(sz) => Ok(Ty::new_array_with_const_len(tcx, t, sz)), + Err(err) => { + // Check whether the lengths are both concrete/known values, + // but are unequal, for better diagnostics. + let sz_a = sz_a.try_to_target_usize(tcx); + let sz_b = sz_b.try_to_target_usize(tcx); + + match (sz_a, sz_b) { + (Some(sz_a_val), Some(sz_b_val)) if sz_a_val != sz_b_val => Err( + TypeError::FixedArraySize(ExpectedFound::new(true, sz_a_val, sz_b_val)), + ), + _ => Err(err), + } + } + } + } + + (ty::Slice(a_t), ty::Slice(b_t)) => { + let t = relation.relate(a_t, b_t)?; + Ok(Ty::new_slice(tcx, t)) + } + + (ty::Tuple(as_), ty::Tuple(bs)) => { + if as_.len() == bs.len() { + Ok(Ty::new_tup_from_iter( + tcx, + iter::zip(as_, bs).map(|(a, b)| relation.relate(a, b)), + )?) + } else if !(as_.is_empty() || bs.is_empty()) { + Err(TypeError::TupleSize(ExpectedFound::new(true, as_.len(), bs.len()))) + } else { + Err(TypeError::Sorts(ExpectedFound::new(true, a, b))) + } + } + + (ty::FnDef(a_def_id, a_args), ty::FnDef(b_def_id, b_args)) if a_def_id == b_def_id => { + let args = relation.relate_item_args(a_def_id, a_args, b_args)?; + Ok(Ty::new_fn_def(tcx, a_def_id, args)) + } + + (ty::FnPtr(a_fty), ty::FnPtr(b_fty)) => { + let fty = relation.relate(a_fty, b_fty)?; + Ok(Ty::new_fn_ptr(tcx, fty)) + } + + // Alias tend to mostly already be handled downstream due to normalization. + (ty::Alias(a_kind, a_data), ty::Alias(b_kind, b_data)) => { + let alias_ty = relation.relate(a_data, b_data)?; + assert_eq!(a_kind, b_kind); + Ok(Ty::new_alias(tcx, a_kind, alias_ty)) + } + + (ty::Pat(a_ty, a_pat), ty::Pat(b_ty, b_pat)) => { + let ty = relation.relate(a_ty, b_ty)?; + let pat = relation.relate(a_pat, b_pat)?; + Ok(Ty::new_pat(tcx, ty, pat)) + } + + _ => Err(TypeError::Sorts(ExpectedFound::new(true, a, b))), + } +} + +/// Relates `a` and `b` structurally, calling the relation for all nested values. +/// Any semantic equality, e.g. of unevaluated consts, and inference variables have +/// to be handled by the caller. +/// +/// FIXME: This is not totally structual, which probably should be fixed. +/// See the HACKs below. +pub fn structurally_relate_consts<I: Interner, R: TypeRelation<I>>( + relation: &mut R, + mut a: I::Const, + mut b: I::Const, +) -> RelateResult<I, I::Const> { + debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); + let tcx = relation.tcx(); + + if tcx.features().generic_const_exprs() { + a = tcx.expand_abstract_consts(a); + b = tcx.expand_abstract_consts(b); + } + + debug!("{}.structurally_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b); + + // Currently, the values that can be unified are primitive types, + // and those that derive both `PartialEq` and `Eq`, corresponding + // to structural-match types. + let is_match = match (a.kind(), b.kind()) { + (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { + // The caller should handle these cases! + panic!("var types encountered in structurally_relate_consts: {:?} {:?}", a, b) + } + + (ty::ConstKind::Error(_), _) => return Ok(a), + (_, ty::ConstKind::Error(_)) => return Ok(b), + + (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index() == b_p.index() => { + // FIXME: Put this back + // debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name"); + true + } + (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2, + (ty::ConstKind::Value(_, a_val), ty::ConstKind::Value(_, b_val)) => a_val == b_val, + + // While this is slightly incorrect, it shouldn't matter for `min_const_generics` + // and is the better alternative to waiting until `generic_const_exprs` can + // be stabilized. + (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def => { + if cfg!(debug_assertions) { + let a_ty = tcx.type_of(au.def).instantiate(tcx, &au.args); + let b_ty = tcx.type_of(bu.def).instantiate(tcx, &bu.args); + assert_eq!(a_ty, b_ty); + } + + let args = relation.relate_with_variance( + ty::Variance::Invariant, + VarianceDiagInfo::default(), + au.args, + bu.args, + )?; + return Ok(Const::new_unevaluated(tcx, ty::UnevaluatedConst { def: au.def, args })); + } + (ty::ConstKind::Expr(ae), ty::ConstKind::Expr(be)) => { + let expr = relation.relate(ae, be)?; + return Ok(Const::new_expr(tcx, expr)); + } + _ => false, + }; + if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(ExpectedFound::new(true, a, b))) } +} + +impl<I: Interner, T: Relate<I>> Relate<I> for ty::Binder<I, T> { + fn relate<R: TypeRelation<I>>( + relation: &mut R, + a: ty::Binder<I, T>, + b: ty::Binder<I, T>, + ) -> RelateResult<I, ty::Binder<I, T>> { + relation.binders(a, b) + } +} + +impl<I: Interner> Relate<I> for ty::PredicatePolarity { + fn relate<R: TypeRelation<I>>( + _relation: &mut R, + a: ty::PredicatePolarity, + b: ty::PredicatePolarity, + ) -> RelateResult<I, ty::PredicatePolarity> { + if a != b { + Err(TypeError::PolarityMismatch(ExpectedFound::new(true, a, b))) + } else { + Ok(a) + } + } +} + +impl<I: Interner> Relate<I> for ty::TraitPredicate<I> { + fn relate<R: TypeRelation<I>>( + relation: &mut R, + a: ty::TraitPredicate<I>, + b: ty::TraitPredicate<I>, + ) -> RelateResult<I, ty::TraitPredicate<I>> { + Ok(ty::TraitPredicate { + trait_ref: relation.relate(a.trait_ref, b.trait_ref)?, + polarity: relation.relate(a.polarity, b.polarity)?, + }) + } +} diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs index 3c24e851d7b..45125fe6191 100644 --- a/compiler/rustc_type_ir/src/solve.rs +++ b/compiler/rustc_type_ir/src/solve.rs @@ -20,7 +20,6 @@ pub type CanonicalResponse<I> = Canonical<I, Response<I>>; pub type QueryResult<I> = Result<CanonicalResponse<I>, NoSolution>; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -#[derive(TypeFoldable_Generic, TypeVisitable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct NoSolution; @@ -60,7 +59,7 @@ impl<I: Interner, P> Goal<I, P> { /// /// This is necessary as we treat nested goals different depending on /// their source. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeVisitable_Generic, TypeFoldable_Generic)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum GoalSource { Misc, @@ -170,7 +169,6 @@ pub enum CandidateSource<I: Interner> { } #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext, TyEncodable, TyDecodable))] pub enum BuiltinImplSource { /// Some builtin impl we don't need to differentiate. This should be used @@ -214,7 +212,6 @@ pub struct Response<I: Interner> { } #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum Certainty { Yes, @@ -252,7 +249,6 @@ impl Certainty { /// Why we failed to evaluate a goal. #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] -#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum MaybeCause { /// We failed due to ambiguity. This ambiguity can either diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 6569f3123aa..71f3862226d 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -1,7 +1,7 @@ #[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; #[cfg(feature = "nightly")] -use rustc_data_structures::unify::{EqUnifyValue, UnifyKey}; +use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue}; #[cfg(feature = "nightly")] use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; @@ -717,14 +717,44 @@ impl FloatTy { } } -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum IntVarValue { + Unknown, IntType(IntTy), UintType(UintTy), } -#[derive(Clone, Copy, PartialEq, Eq)] -pub struct FloatVarValue(pub FloatTy); +impl IntVarValue { + pub fn is_known(self) -> bool { + match self { + IntVarValue::IntType(_) | IntVarValue::UintType(_) => true, + IntVarValue::Unknown => false, + } + } + + pub fn is_unknown(self) -> bool { + !self.is_known() + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum FloatVarValue { + Unknown, + Known(FloatTy), +} + +impl FloatVarValue { + pub fn is_known(self) -> bool { + match self { + FloatVarValue::Known(_) => true, + FloatVarValue::Unknown => false, + } + } + + pub fn is_unknown(self) -> bool { + !self.is_known() + } +} rustc_index::newtype_index! { /// A **ty**pe **v**ariable **ID**. @@ -809,11 +839,28 @@ impl UnifyKey for TyVid { } #[cfg(feature = "nightly")] -impl EqUnifyValue for IntVarValue {} +impl UnifyValue for IntVarValue { + type Error = NoError; + + fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> { + match (*value1, *value2) { + (IntVarValue::Unknown, IntVarValue::Unknown) => Ok(IntVarValue::Unknown), + ( + IntVarValue::Unknown, + known @ (IntVarValue::UintType(_) | IntVarValue::IntType(_)), + ) + | ( + known @ (IntVarValue::UintType(_) | IntVarValue::IntType(_)), + IntVarValue::Unknown, + ) => Ok(known), + _ => panic!("differing ints should have been resolved first"), + } + } +} #[cfg(feature = "nightly")] impl UnifyKey for IntVid { - type Value = Option<IntVarValue>; + type Value = IntVarValue; #[inline] // make this function eligible for inlining - it is quite hot. fn index(&self) -> u32 { self.as_u32() @@ -828,11 +875,26 @@ impl UnifyKey for IntVid { } #[cfg(feature = "nightly")] -impl EqUnifyValue for FloatVarValue {} +impl UnifyValue for FloatVarValue { + type Error = NoError; + + fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> { + match (*value1, *value2) { + (FloatVarValue::Unknown, FloatVarValue::Unknown) => Ok(FloatVarValue::Unknown), + (FloatVarValue::Unknown, FloatVarValue::Known(known)) + | (FloatVarValue::Known(known), FloatVarValue::Unknown) => { + Ok(FloatVarValue::Known(known)) + } + (FloatVarValue::Known(_), FloatVarValue::Known(_)) => { + panic!("differing floats should have been resolved first") + } + } + } +} #[cfg(feature = "nightly")] impl UnifyKey for FloatVid { - type Value = Option<FloatVarValue>; + type Value = FloatVarValue; #[inline] fn index(&self) -> u32 { self.as_u32() @@ -860,21 +922,6 @@ impl<CTX> HashStable<CTX> for InferTy { } } -impl fmt::Debug for IntVarValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - IntVarValue::IntType(ref v) => v.fmt(f), - IntVarValue::UintType(ref v) => v.fmt(f), - } - } -} - -impl fmt::Debug for FloatVarValue { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - impl fmt::Display for InferTy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use InferTy::*; diff --git a/compiler/stable_mir/Cargo.toml b/compiler/stable_mir/Cargo.toml index c61e217bf9f..4ed61152736 100644 --- a/compiler/stable_mir/Cargo.toml +++ b/compiler/stable_mir/Cargo.toml @@ -4,5 +4,4 @@ version = "0.1.0-preview" edition = "2021" [dependencies] -tracing = "0.1" scoped-tls = "1.0" diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 858ce5301d8..085dfd9ea89 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -11,10 +11,10 @@ use crate::mir::mono::{Instance, InstanceDef, StaticDef}; use crate::mir::{BinOp, Body, Place, UnOp}; use crate::target::MachineInfo; use crate::ty::{ - AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef, + AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, FieldDef, FnDef, ForeignDef, ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates, Generics, - ImplDef, ImplTrait, IntrinsicDef, LineInfo, PolyFnSig, RigidTy, Span, TraitDecl, TraitDef, Ty, - TyKind, UintTy, VariantDef, + ImplDef, ImplTrait, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span, TraitDecl, + TraitDef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef, }; use crate::{ mir, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls, ItemKind, @@ -109,19 +109,21 @@ pub trait Context { fn variant_fields(&self, def: VariantDef) -> Vec<FieldDef>; /// Evaluate constant as a target usize. - fn eval_target_usize(&self, cnst: &Const) -> Result<u64, Error>; + fn eval_target_usize(&self, cnst: &MirConst) -> Result<u64, Error>; + fn eval_target_usize_ty(&self, cnst: &TyConst) -> Result<u64, Error>; /// Create a new zero-sized constant. - fn try_new_const_zst(&self, ty: Ty) -> Result<Const, Error>; + fn try_new_const_zst(&self, ty: Ty) -> Result<MirConst, Error>; /// Create a new constant that represents the given string value. - fn new_const_str(&self, value: &str) -> Const; + fn new_const_str(&self, value: &str) -> MirConst; /// Create a new constant that represents the given boolean value. - fn new_const_bool(&self, value: bool) -> Const; + fn new_const_bool(&self, value: bool) -> MirConst; /// Create a new constant that represents the given value. - fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<Const, Error>; + fn try_new_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<MirConst, Error>; + fn try_new_ty_const_uint(&self, value: u128, uint_ty: UintTy) -> Result<TyConst, Error>; /// Create a new type from the given kind. fn new_rigid_ty(&self, kind: RigidTy) -> Ty; @@ -136,11 +138,13 @@ pub trait Context { fn def_ty_with_args(&self, item: DefId, args: &GenericArgs) -> Ty; /// Returns literal value of a const as a string. - fn const_pretty(&self, cnst: &Const) -> String; + fn mir_const_pretty(&self, cnst: &MirConst) -> String; /// `Span` of an item fn span_of_an_item(&self, def_id: DefId) -> Span; + fn ty_const_pretty(&self, ct: TyConstId) -> String; + /// Obtain the representation of a type. fn ty_pretty(&self, ty: Ty) -> String; diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 4c779ae96a8..43e4682dc10 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -1,8 +1,8 @@ use crate::compiler_interface::with; use crate::mir::pretty::function_body; use crate::ty::{ - AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind, - VariantIdx, + AdtDef, ClosureDef, CoroutineDef, GenericArgs, MirConst, Movability, Region, RigidTy, Ty, + TyConst, TyKind, VariantIdx, }; use crate::{Error, Opaque, Span, Symbol}; use std::io; @@ -524,7 +524,7 @@ pub enum Rvalue { /// Corresponds to source code like `[x; 32]`. /// /// [#74836]: https://github.com/rust-lang/rust/issues/74836 - Repeat(Operand, Const), + Repeat(Operand, TyConst), /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`. /// @@ -718,7 +718,7 @@ pub enum VarDebugInfoContents { pub struct ConstOperand { pub span: Span, pub user_ty: Option<UserTypeAnnotationIndex>, - pub const_: Const, + pub const_: MirConst, } // In MIR ProjectionElem is parameterized on the second Field argument and the Index argument. This @@ -833,7 +833,7 @@ type UserTypeAnnotationIndex = usize; pub struct Constant { pub span: Span, pub user_ty: Option<UserTypeAnnotationIndex>, - pub literal: Const, + pub literal: MirConst, } /// The possible branch sites of a [TerminatorKind::SwitchInt]. diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs index 580dc1a2b88..2fb180b84c7 100644 --- a/compiler/stable_mir/src/mir/pretty.rs +++ b/compiler/stable_mir/src/mir/pretty.rs @@ -1,5 +1,5 @@ use crate::mir::{Operand, Place, Rvalue, StatementKind, UnwindAction, VarDebugInfoContents}; -use crate::ty::{Const, IndexedVal, Ty}; +use crate::ty::{IndexedVal, MirConst, Ty, TyConst}; use crate::{with, Body, Mutability}; use fmt::{Display, Formatter}; use std::fmt::Debug; @@ -46,7 +46,7 @@ pub(crate) fn function_body<W: Write>(writer: &mut W, body: &Body, name: &str) - VarDebugInfoContents::Place(place) => { format!("{place:?}") } - VarDebugInfoContents::Const(constant) => pretty_const(&constant.const_), + VarDebugInfoContents::Const(constant) => pretty_mir_const(&constant.const_), }; writeln!(writer, " debug {} => {};", info.name, content) })?; @@ -310,12 +310,16 @@ fn pretty_operand(operand: &Operand) -> String { Operand::Move(mv) => { format!("move {:?}", mv) } - Operand::Constant(cnst) => pretty_const(&cnst.literal), + Operand::Constant(cnst) => pretty_mir_const(&cnst.literal), } } -fn pretty_const(literal: &Const) -> String { - with(|cx| cx.const_pretty(literal)) +fn pretty_mir_const(literal: &MirConst) -> String { + with(|cx| cx.mir_const_pretty(literal)) +} + +fn pretty_ty_const(ct: &TyConst) -> String { + with(|cx| cx.ty_const_pretty(ct.id)) } fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> { @@ -359,7 +363,7 @@ fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> { write!(writer, "{kind}{:?}", place) } Rvalue::Repeat(op, cnst) => { - write!(writer, "{} \" \" {}", &pretty_operand(op), cnst.ty()) + write!(writer, "{} \" \" {}", &pretty_operand(op), &pretty_ty_const(cnst)) } Rvalue::ShallowInitBox(_, _) => Ok(()), Rvalue::ThreadLocalRef(item) => { diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index 24296e9e877..10f30083dc2 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -36,7 +36,7 @@ //! variant argument) that does not require visiting. use crate::mir::*; -use crate::ty::{Const, GenericArgs, Region, Ty}; +use crate::ty::{GenericArgs, MirConst, Region, Ty, TyConst}; use crate::{Error, Opaque, Span}; pub trait MirVisitor { @@ -112,8 +112,13 @@ pub trait MirVisitor { self.super_constant(constant, location) } - fn visit_const(&mut self, constant: &Const, location: Location) { - self.super_const(constant, location) + fn visit_mir_const(&mut self, constant: &MirConst, location: Location) { + self.super_mir_const(constant, location) + } + + fn visit_ty_const(&mut self, constant: &TyConst, location: Location) { + let _ = location; + self.super_ty_const(constant) } fn visit_region(&mut self, region: &Region, location: Location) { @@ -339,7 +344,7 @@ pub trait MirVisitor { } Rvalue::Repeat(op, constant) => { self.visit_operand(op, location); - self.visit_const(constant, location); + self.visit_ty_const(constant, location); } Rvalue::ShallowInitBox(op, ty) => { self.visit_ty(ty, location); @@ -378,14 +383,18 @@ pub trait MirVisitor { fn super_constant(&mut self, constant: &Constant, location: Location) { let Constant { span, user_ty: _, literal } = constant; self.visit_span(span); - self.visit_const(literal, location); + self.visit_mir_const(literal, location); } - fn super_const(&mut self, constant: &Const, location: Location) { - let Const { kind: _, ty, id: _ } = constant; + fn super_mir_const(&mut self, constant: &MirConst, location: Location) { + let MirConst { kind: _, ty, id: _ } = constant; self.visit_ty(ty, location); } + fn super_ty_const(&mut self, constant: &TyConst) { + let _ = constant; + } + fn super_region(&mut self, region: &Region) { let _ = region; } @@ -407,7 +416,7 @@ pub trait MirVisitor { self.visit_place(place, PlaceContext::NON_USE, location); } VarDebugInfoContents::Const(constant) => { - self.visit_const(&constant.const_, location); + self.visit_mir_const(&constant.const_, location); } } } diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 50bf0a5d74e..bcbe87f7303 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -28,11 +28,11 @@ impl Ty { /// Create a new array type. pub fn try_new_array(elem_ty: Ty, size: u64) -> Result<Ty, Error> { - Ok(Ty::from_rigid_kind(RigidTy::Array(elem_ty, Const::try_from_target_usize(size)?))) + Ok(Ty::from_rigid_kind(RigidTy::Array(elem_ty, TyConst::try_from_target_usize(size)?))) } /// Create a new array type from Const length. - pub fn new_array_with_const_len(elem_ty: Ty, len: Const) -> Ty { + pub fn new_array_with_const_len(elem_ty: Ty, len: TyConst) -> Ty { Ty::from_rigid_kind(RigidTy::Array(elem_ty, len)) } @@ -101,24 +101,66 @@ impl Ty { /// Represents a pattern in the type system #[derive(Clone, Debug, Eq, PartialEq)] pub enum Pattern { - Range { start: Option<Const>, end: Option<Const>, include_end: bool }, + Range { start: Option<TyConst>, end: Option<TyConst>, include_end: bool }, } -/// Represents a constant in MIR or from the Type system. +/// Represents a constant in the type system #[derive(Clone, Debug, Eq, PartialEq)] -pub struct Const { +pub struct TyConst { + pub(crate) kind: TyConstKind, + pub id: TyConstId, +} + +impl TyConst { + pub fn new(kind: TyConstKind, id: TyConstId) -> TyConst { + Self { kind, id } + } + + /// Retrieve the constant kind. + pub fn kind(&self) -> &TyConstKind { + &self.kind + } + + /// Creates an interned usize constant. + fn try_from_target_usize(val: u64) -> Result<Self, Error> { + with(|cx| cx.try_new_ty_const_uint(val.into(), UintTy::Usize)) + } + + /// Try to evaluate to a target `usize`. + pub fn eval_target_usize(&self) -> Result<u64, Error> { + with(|cx| cx.eval_target_usize_ty(self)) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum TyConstKind { + Param(ParamConst), + Bound(DebruijnIndex, BoundVar), + Unevaluated(ConstDef, GenericArgs), + + // FIXME: These should be a valtree + Value(Ty, Allocation), + ZSTValue(Ty), +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct TyConstId(usize); + +/// Represents a constant in MIR +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct MirConst { /// The constant kind. pub(crate) kind: ConstantKind, /// The constant type. pub(crate) ty: Ty, /// Used for internal tracking of the internal constant. - pub id: ConstId, + pub id: MirConstId, } -impl Const { +impl MirConst { /// Build a constant. Note that this should only be used by the compiler. - pub fn new(kind: ConstantKind, ty: Ty, id: ConstId) -> Const { - Const { kind, ty, id } + pub fn new(kind: ConstantKind, ty: Ty, id: MirConstId) -> MirConst { + MirConst { kind, ty, id } } /// Retrieve the constant kind. @@ -131,11 +173,6 @@ impl Const { self.ty } - /// Creates an interned usize constant. - fn try_from_target_usize(val: u64) -> Result<Self, Error> { - with(|cx| cx.try_new_const_uint(val.into(), UintTy::Usize)) - } - /// Try to evaluate to a target `usize`. pub fn eval_target_usize(&self) -> Result<u64, Error> { with(|cx| cx.eval_target_usize(self)) @@ -143,7 +180,7 @@ impl Const { /// Create a constant that represents a new zero-sized constant of type T. /// Fails if the type is not a ZST or if it doesn't have a known size. - pub fn try_new_zero_sized(ty: Ty) -> Result<Const, Error> { + pub fn try_new_zero_sized(ty: Ty) -> Result<MirConst, Error> { with(|cx| cx.try_new_const_zst(ty)) } @@ -152,23 +189,23 @@ impl Const { /// Note that there is no guarantee today about duplication of the same constant. /// I.e.: Calling this function multiple times with the same argument may or may not return /// the same allocation. - pub fn from_str(value: &str) -> Const { + pub fn from_str(value: &str) -> MirConst { with(|cx| cx.new_const_str(value)) } /// Build a new constant that represents the given boolean value. - pub fn from_bool(value: bool) -> Const { + pub fn from_bool(value: bool) -> MirConst { with(|cx| cx.new_const_bool(value)) } /// Build a new constant that represents the given unsigned integer. - pub fn try_from_uint(value: u128, uint_ty: UintTy) -> Result<Const, Error> { + pub fn try_from_uint(value: u128, uint_ty: UintTy) -> Result<MirConst, Error> { with(|cx| cx.try_new_const_uint(value, uint_ty)) } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct ConstId(usize); +pub struct MirConstId(usize); type Ident = Opaque; @@ -484,7 +521,7 @@ pub enum RigidTy { Adt(AdtDef, GenericArgs), Foreign(ForeignDef), Str, - Array(Ty, Const), + Array(Ty, TyConst), Pat(Ty, Pattern), Slice(Ty), RawPtr(Ty, Mutability), @@ -866,7 +903,7 @@ impl std::ops::Index<ParamTy> for GenericArgs { } impl std::ops::Index<ParamConst> for GenericArgs { - type Output = Const; + type Output = TyConst; fn index(&self, index: ParamConst) -> &Self::Output { self.0[index.index as usize].expect_const() @@ -877,7 +914,7 @@ impl std::ops::Index<ParamConst> for GenericArgs { pub enum GenericArgKind { Lifetime(Region), Type(Ty), - Const(Const), + Const(TyConst), } impl GenericArgKind { @@ -894,7 +931,7 @@ impl GenericArgKind { /// Panic if this generic argument is not a const, otherwise /// return the const. #[track_caller] - pub fn expect_const(&self) -> &Const { + pub fn expect_const(&self) -> &TyConst { match self { GenericArgKind::Const(c) => c, _ => panic!("{self:?}"), @@ -913,7 +950,7 @@ impl GenericArgKind { #[derive(Clone, Debug, Eq, PartialEq)] pub enum TermKind { Type(Ty), - Const(Const), + Const(TyConst), } #[derive(Clone, Debug, Eq, PartialEq)] @@ -1202,6 +1239,7 @@ impl Allocation { #[derive(Clone, Debug, Eq, PartialEq)] pub enum ConstantKind { + Ty(TyConst), Allocated(Allocation), Unevaluated(UnevaluatedConst), Param(ParamConst), @@ -1335,7 +1373,7 @@ pub enum PredicateKind { ObjectSafe(TraitDef), SubType(SubtypePredicate), Coerce(CoercePredicate), - ConstEquate(Const, Const), + ConstEquate(TyConst, TyConst), Ambiguous, AliasRelate(TermKind, TermKind, AliasRelationDirection), } @@ -1346,9 +1384,9 @@ pub enum ClauseKind { RegionOutlives(RegionOutlivesPredicate), TypeOutlives(TypeOutlivesPredicate), Projection(ProjectionPredicate), - ConstArgHasType(Const, Ty), + ConstArgHasType(TyConst, Ty), WellFormed(GenericArgKind), - ConstEvaluatable(Const), + ConstEvaluatable(TyConst), } #[derive(Clone, Debug, Eq, PartialEq)] @@ -1426,7 +1464,8 @@ macro_rules! index_impl { }; } -index_impl!(ConstId); +index_impl!(TyConstId); +index_impl!(MirConstId); index_impl!(Ty); index_impl!(Span); diff --git a/compiler/stable_mir/src/visitor.rs b/compiler/stable_mir/src/visitor.rs index 2d7159f87fe..fc1da8fafe4 100644 --- a/compiler/stable_mir/src/visitor.rs +++ b/compiler/stable_mir/src/visitor.rs @@ -1,10 +1,10 @@ use std::ops::ControlFlow; -use crate::Opaque; +use crate::{ty::TyConst, Opaque}; use super::ty::{ - Allocation, Binder, Const, ConstDef, ExistentialPredicate, FnSig, GenericArgKind, GenericArgs, - Promoted, Region, RigidTy, TermKind, Ty, UnevaluatedConst, + Allocation, Binder, ConstDef, ExistentialPredicate, FnSig, GenericArgKind, GenericArgs, + MirConst, Promoted, Region, RigidTy, TermKind, Ty, UnevaluatedConst, }; pub trait Visitor: Sized { @@ -12,7 +12,7 @@ pub trait Visitor: Sized { fn visit_ty(&mut self, ty: &Ty) -> ControlFlow<Self::Break> { ty.super_visit(self) } - fn visit_const(&mut self, c: &Const) -> ControlFlow<Self::Break> { + fn visit_const(&mut self, c: &TyConst) -> ControlFlow<Self::Break> { c.super_visit(self) } fn visit_reg(&mut self, reg: &Region) -> ControlFlow<Self::Break> { @@ -42,12 +42,32 @@ impl Visitable for Ty { } } -impl Visitable for Const { +impl Visitable for TyConst { fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { visitor.visit_const(self) } fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + match &self.kind { + crate::ty::TyConstKind::Param(_) => {} + crate::ty::TyConstKind::Bound(_, _) => {} + crate::ty::TyConstKind::Unevaluated(_, args) => args.visit(visitor)?, + crate::ty::TyConstKind::Value(ty, alloc) => { + alloc.visit(visitor)?; + ty.visit(visitor)?; + } + crate::ty::TyConstKind::ZSTValue(ty) => ty.visit(visitor)?, + } + ControlFlow::Continue(()) + } +} + +impl Visitable for MirConst { + fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { + self.super_visit(visitor) + } + fn super_visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> { match &self.kind() { + super::ty::ConstantKind::Ty(ct) => ct.visit(visitor)?, super::ty::ConstantKind::Allocated(alloc) => alloc.visit(visitor)?, super::ty::ConstantKind::Unevaluated(uv) => uv.visit(visitor)?, super::ty::ConstantKind::Param(_) | super::ty::ConstantKind::ZeroSized => {} diff --git a/config.example.toml b/config.example.toml index 61655dad638..fb45493ec4a 100644 --- a/config.example.toml +++ b/config.example.toml @@ -389,8 +389,8 @@ # a Nix toolchain on non-NixOS distributions. #patch-binaries-for-nix = false -# Collect information and statistics about the current build and writes it to -# disk. Enabling this or not has no impact on the resulting build output. The +# Collect information and statistics about the current build, and write it to +# disk. Enabling this has no impact on the resulting build output. The # schema of the file generated by the build metrics feature is unstable, and # this is not intended to be used during local development. #metrics = false diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 0b04fb4a274..a391141827e 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -1216,7 +1216,6 @@ impl<T, A: Allocator> BinaryHeap<T, A> { /// Basic usage: /// /// ``` - /// #![feature(binary_heap_as_slice)] /// use std::collections::BinaryHeap; /// use std::io::{self, Write}; /// @@ -1225,7 +1224,7 @@ impl<T, A: Allocator> BinaryHeap<T, A> { /// io::sink().write(heap.as_slice()).unwrap(); /// ``` #[must_use] - #[unstable(feature = "binary_heap_as_slice", issue = "83659")] + #[stable(feature = "binary_heap_as_slice", since = "CURRENT_RUSTC_VERSION")] pub fn as_slice(&self) -> &[T] { self.data.as_slice() } diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 1c90c171a15..01510a61405 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1705,7 +1705,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { unsafe { self.current = unlinked_node.as_ref().next; self.list.unlink_node(unlinked_node); - let unlinked_node = Box::from_raw(unlinked_node.as_ptr()); + let unlinked_node = Box::from_raw_in(unlinked_node.as_ptr(), &self.list.alloc); Some(unlinked_node.element) } } @@ -1946,7 +1946,7 @@ where if (self.pred)(&mut node.as_mut().element) { // `unlink_node` is okay with aliasing `element` references. self.list.unlink_node(node); - return Some(Box::from_raw(node.as_ptr()).element); + return Some(Box::from_raw_in(node.as_ptr(), &self.list.alloc).element); } } } diff --git a/library/alloc/src/collections/linked_list/tests.rs b/library/alloc/src/collections/linked_list/tests.rs index 8dcd59d12d9..d3744c5a9d0 100644 --- a/library/alloc/src/collections/linked_list/tests.rs +++ b/library/alloc/src/collections/linked_list/tests.rs @@ -1164,3 +1164,42 @@ fn test_drop_panic() { assert_eq!(unsafe { DROPS }, 8); } + +#[test] +fn test_allocator() { + use core::alloc::AllocError; + use core::alloc::Allocator; + use core::alloc::Layout; + use core::cell::Cell; + + struct A { + has_allocated: Cell<bool>, + has_deallocated: Cell<bool>, + } + + unsafe impl Allocator for A { + fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> { + assert!(!self.has_allocated.get()); + self.has_allocated.set(true); + + Global.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { + assert!(!self.has_deallocated.get()); + self.has_deallocated.set(true); + + unsafe { Global.deallocate(ptr, layout) } + } + } + + let alloc = &A { has_allocated: Cell::new(false), has_deallocated: Cell::new(false) }; + { + let mut list = LinkedList::new_in(alloc); + list.push_back(5u32); + list.remove(0); + } + + assert!(alloc.has_allocated.get()); + assert!(alloc.has_deallocated.get()); +} diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 4ac0c9b15be..4749b8880fb 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -121,7 +121,6 @@ #![feature(deref_pure_trait)] #![feature(dispatch_from_dyn)] #![feature(error_generic_member_access)] -#![feature(error_in_core)] #![feature(exact_size_is_empty)] #![feature(extend_one)] #![feature(fmt_internals)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 875c24c28e4..f3a4803e0d4 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -257,8 +257,6 @@ use core::intrinsics::abort; #[cfg(not(no_global_oom_handling))] use core::iter; use core::marker::{PhantomData, Unsize}; -#[cfg(not(no_global_oom_handling))] -use core::mem::size_of_val; use core::mem::{self, align_of_val_raw, forget, ManuallyDrop}; use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 7dcaa59dcd1..5a4f9df614e 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -18,8 +18,6 @@ use core::intrinsics::abort; #[cfg(not(no_global_oom_handling))] use core::iter; use core::marker::{PhantomData, Unsize}; -#[cfg(not(no_global_oom_handling))] -use core::mem::size_of_val; use core::mem::{self, align_of_val_raw}; use core::ops::{CoerceUnsized, Deref, DerefPure, DispatchFromDyn, Receiver}; use core::panic::{RefUnwindSafe, UnwindSafe}; diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 8451be63c2b..89538f272f0 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -24,7 +24,6 @@ #![feature(binary_heap_into_iter_sorted)] #![feature(binary_heap_drain_sorted)] #![feature(slice_ptr_get)] -#![feature(binary_heap_as_slice)] #![feature(inplace_iteration)] #![feature(iter_advance_by)] #![feature(iter_next_chunk)] diff --git a/library/alloc/tests/vec_deque_alloc_error.rs b/library/alloc/tests/vec_deque_alloc_error.rs index c11f4556da9..8b516ddbc5c 100644 --- a/library/alloc/tests/vec_deque_alloc_error.rs +++ b/library/alloc/tests/vec_deque_alloc_error.rs @@ -8,6 +8,7 @@ use std::{ }; #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_shrink_to_unwind() { // This tests that `shrink_to` leaves the deque in a consistent state when // the call to `RawVec::shrink_to_fit` unwinds. The code is adapted from #123369 diff --git a/library/backtrace b/library/backtrace -Subproject 5e05efa87905fb5b351a2bc5644d60c57d6d932 +Subproject 72265bea210891ae47bbe6d4f17b493ef060661 diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index ac026de95da..efa0fd7b56c 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -82,6 +82,20 @@ //! //! The corresponding [`Sync`] version of `OnceCell<T>` is [`OnceLock<T>`]. //! +//! ## `LazyCell<T, F>` +//! +//! A common pattern with OnceCell is, for a given OnceCell, to use the same function on every +//! call to [`OnceCell::get_or_init`] with that cell. This is what is offered by [`LazyCell`], +//! which pairs cells of `T` with functions of `F`, and always calls `F` before it yields `&T`. +//! This happens implicitly by simply attempting to dereference the LazyCell to get its contents, +//! so its use is much more transparent with a place which has been initialized by a constant. +//! +//! More complicated patterns that don't fit this description can be built on `OnceCell<T>` instead. +//! +//! `LazyCell` works by providing an implementation of `impl Deref` that calls the function, +//! so you can just use it by dereference (e.g. `*lazy_cell` or `lazy_cell.deref()`). +//! +//! The corresponding [`Sync`] version of `LazyCell<T, F>` is [`LazyLock<T, F>`]. //! //! # When to choose interior mutability //! @@ -230,6 +244,7 @@ //! [`RwLock<T>`]: ../../std/sync/struct.RwLock.html //! [`Mutex<T>`]: ../../std/sync/struct.Mutex.html //! [`OnceLock<T>`]: ../../std/sync/struct.OnceLock.html +//! [`LazyLock<T, F>`]: ../../std/sync/struct.LazyLock.html //! [`Sync`]: ../../std/marker/trait.Sync.html //! [`atomic`]: crate::sync::atomic @@ -238,7 +253,7 @@ use crate::cmp::Ordering; use crate::fmt::{self, Debug, Display}; use crate::marker::{PhantomData, Unsize}; -use crate::mem::{self, size_of}; +use crate::mem; use crate::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn}; use crate::ptr::{self, NonNull}; diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs index a7c3dfc982d..872b4da4dbf 100644 --- a/library/core/src/cell/once.rs +++ b/library/core/src/cell/once.rs @@ -2,12 +2,12 @@ use crate::cell::UnsafeCell; use crate::fmt; use crate::mem; -/// A cell which can be written to only once. +/// A cell which can nominally be written to only once. /// /// This allows obtaining a shared `&T` reference to its inner value without copying or replacing /// it (unlike [`Cell`]), and without runtime borrow checks (unlike [`RefCell`]). However, /// only immutable references can be obtained unless one has a mutable reference to the cell -/// itself. +/// itself. In the same vein, the cell can only be re-initialized with such a mutable reference. /// /// For a thread-safe version of this struct, see [`std::sync::OnceLock`]. /// diff --git a/library/core/src/error.rs b/library/core/src/error.rs index a3f2b767054..da18fdc6e1d 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -1,5 +1,5 @@ #![doc = include_str!("error.md")] -#![unstable(feature = "error_in_core", issue = "103765")] +#![stable(feature = "error_in_core", since = "CURRENT_RUSTC_VERSION")] #[cfg(test)] mod tests; @@ -130,7 +130,6 @@ pub trait Error: Debug + Display { /// /// ```rust /// #![feature(error_generic_member_access)] - /// #![feature(error_in_core)] /// use core::fmt; /// use core::error::{request_ref, Request}; /// @@ -361,8 +360,7 @@ impl dyn Error { /// Get a string value from an error. /// /// ```rust -/// # #![feature(error_generic_member_access)] -/// # #![feature(error_in_core)] +/// #![feature(error_generic_member_access)] /// use std::error::Error; /// use core::error::request_value; /// @@ -385,8 +383,7 @@ where /// Get a string reference from an error. /// /// ```rust -/// # #![feature(error_generic_member_access)] -/// # #![feature(error_in_core)] +/// #![feature(error_generic_member_access)] /// use core::error::Error; /// use core::error::request_ref; /// @@ -458,7 +455,6 @@ where /// /// ``` /// #![feature(error_generic_member_access)] -/// #![feature(error_in_core)] /// use core::fmt; /// use core::error::Request; /// use core::error::request_ref; @@ -529,7 +525,6 @@ impl<'a> Request<'a> { /// /// ```rust /// #![feature(error_generic_member_access)] - /// #![feature(error_in_core)] /// /// use core::error::Request; /// @@ -564,7 +559,6 @@ impl<'a> Request<'a> { /// /// ```rust /// #![feature(error_generic_member_access)] - /// #![feature(error_in_core)] /// /// use core::error::Request; /// @@ -600,7 +594,6 @@ impl<'a> Request<'a> { /// /// ```rust /// #![feature(error_generic_member_access)] - /// #![feature(error_in_core)] /// /// use core::error::Request; /// @@ -633,7 +626,6 @@ impl<'a> Request<'a> { /// /// ```rust /// #![feature(error_generic_member_access)] - /// #![feature(error_in_core)] /// /// use core::error::Request; /// @@ -700,7 +692,6 @@ impl<'a> Request<'a> { /// /// ```rust /// #![feature(error_generic_member_access)] - /// #![feature(error_in_core)] /// /// use core::error::Request; /// use core::error::request_value; @@ -788,7 +779,6 @@ impl<'a> Request<'a> { /// /// ```rust /// #![feature(error_generic_member_access)] - /// #![feature(error_in_core)] /// /// use core::error::Request; /// use core::error::request_ref; diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index ab2158394bf..3a5a5af8bf5 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -212,6 +212,7 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\ macro_rules! impl_Display { ($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => { + #[cfg(not(feature = "optimize_for_size"))] fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { // 2^128 is about 3*10^38, so 39 gives an extra byte of space let mut buf = [MaybeUninit::<u8>::uninit(); 39]; @@ -277,6 +278,38 @@ macro_rules! impl_Display { f.pad_integral(is_nonnegative, "", buf_slice) } + #[cfg(feature = "optimize_for_size")] + fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // 2^128 is about 3*10^38, so 39 gives an extra byte of space + let mut buf = [MaybeUninit::<u8>::uninit(); 39]; + let mut curr = buf.len(); + let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); + + // SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning + // `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at + // each step this is kept the same as `n` is divided. Since `n` is always + // non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]` + // is safe to access. + unsafe { + loop { + curr -= 1; + buf_ptr.add(curr).write((n % 10) as u8 + b'0'); + n /= 10; + + if n == 0 { + break; + } + } + } + + // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid UTF-8 + let buf_slice = unsafe { + str::from_utf8_unchecked( + slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr)) + }; + f.pad_integral(is_nonnegative, "", buf_slice) + } + $(#[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for $t { #[allow(unused_comparisons)] diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 89e0b670995..28397fe4619 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -65,7 +65,6 @@ use crate::marker::DiscriminantKind; use crate::marker::Tuple; -use crate::mem::align_of; use crate::ptr; use crate::ub_checks; diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index fa5bb28adff..ec8488009b9 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -20,7 +20,7 @@ //! //! #[custom_mir(dialect = "built")] //! pub fn simple(x: i32) -> i32 { -//! mir!( +//! mir! { //! let temp2: i32; //! //! { @@ -33,7 +33,7 @@ //! RET = temp2; //! Return() //! } -//! ) +//! } //! } //! ``` //! @@ -71,7 +71,7 @@ //! //! #[custom_mir(dialect = "built")] //! pub fn choose_load(a: &i32, b: &i32, c: bool) -> i32 { -//! mir!( +//! mir! { //! { //! match c { //! true => t, @@ -93,20 +93,22 @@ //! RET = *temp; //! Return() //! } -//! ) +//! } //! } //! //! #[custom_mir(dialect = "built")] //! fn unwrap_unchecked<T>(opt: Option<T>) -> T { -//! mir!({ -//! RET = Move(Field(Variant(opt, 1), 0)); -//! Return() -//! }) +//! mir! { +//! { +//! RET = Move(Field(Variant(opt, 1), 0)); +//! Return() +//! } +//! } //! } //! //! #[custom_mir(dialect = "runtime", phase = "optimized")] //! fn push_and_pop<T>(v: &mut Vec<T>, value: T) { -//! mir!( +//! mir! { //! let _unused; //! let popped; //! @@ -125,19 +127,19 @@ //! ret = { //! Return() //! } -//! ) +//! } //! } //! //! #[custom_mir(dialect = "runtime", phase = "optimized")] //! fn annotated_return_type() -> (i32, bool) { -//! mir!( +//! mir! { //! type RET = (i32, bool); //! { //! RET.0 = 1; //! RET.1 = true; //! Return() //! } -//! ) +//! } //! } //! ``` //! @@ -152,7 +154,7 @@ //! //! #[custom_mir(dialect = "built")] //! fn borrow_error(should_init: bool) -> i32 { -//! mir!( +//! mir! { //! let temp: i32; //! //! { @@ -171,7 +173,7 @@ //! RET = temp; //! Return() //! } -//! ) +//! } //! } //! ``` //! @@ -179,7 +181,7 @@ //! error[E0381]: used binding is possibly-uninitialized //! --> test.rs:24:13 //! | -//! 8 | / mir!( +//! 8 | / mir! { //! 9 | | let temp: i32; //! 10 | | //! 11 | | { @@ -191,7 +193,7 @@ //! | | ^^^^^^^^^^ value used here but it is possibly-uninitialized //! 25 | | Return() //! 26 | | } -//! 27 | | ) +//! 27 | | } //! | |_____- binding declared here but left uninitialized //! //! error: aborting due to 1 previous error @@ -407,18 +409,22 @@ define!( /// /// #[custom_mir(dialect = "built")] /// fn unwrap_deref(opt: Option<&i32>) -> i32 { - /// mir!({ - /// RET = *Field::<&i32>(Variant(opt, 1), 0); - /// Return() - /// }) + /// mir! { + /// { + /// RET = *Field::<&i32>(Variant(opt, 1), 0); + /// Return() + /// } + /// } /// } /// /// #[custom_mir(dialect = "built")] /// fn set(opt: &mut Option<i32>) { - /// mir!({ - /// place!(Field(Variant(*opt, 1), 0)) = 5; - /// Return() - /// }) + /// mir! { + /// { + /// place!(Field(Variant(*opt, 1), 0)) = 5; + /// Return() + /// } + /// } /// } /// ``` fn Field<F>(place: (), field: u32) -> F @@ -455,7 +461,7 @@ define!( /// your MIR into something that is easier to parse in the compiler. #[rustc_macro_transparency = "transparent"] pub macro mir { - ( + { $(type RET = $ret_ty:ty ;)? $(let $local_decl:ident $(: $local_decl_ty:ty)? ;)* $(debug $dbg_name:ident => $dbg_data:expr ;)* @@ -469,7 +475,7 @@ pub macro mir { $($block:tt)* } )* - ) => {{ + } => {{ // First, we declare all basic blocks. __internal_declare_basic_blocks!($( $block_name $(($block_cleanup))? diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index bcaac2f42cf..dad3d79acb1 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -4,8 +4,8 @@ use crate::ops::Try; /// An iterator that links two iterators together, in a chain. /// -/// This `struct` is created by [`Iterator::chain`]. See its documentation -/// for more. +/// This `struct` is created by [`chain`] or [`Iterator::chain`]. See their +/// documentation for more. /// /// # Examples /// @@ -38,6 +38,39 @@ impl<A, B> Chain<A, B> { } } +/// Converts the arguments to iterators and links them together, in a chain. +/// +/// See the documentation of [`Iterator::chain`] for more. +/// +/// # Examples +/// +/// ``` +/// #![feature(iter_chain)] +/// +/// use std::iter::chain; +/// +/// let a = [1, 2, 3]; +/// let b = [4, 5, 6]; +/// +/// let mut iter = chain(a, b); +/// +/// assert_eq!(iter.next(), Some(1)); +/// assert_eq!(iter.next(), Some(2)); +/// assert_eq!(iter.next(), Some(3)); +/// assert_eq!(iter.next(), Some(4)); +/// assert_eq!(iter.next(), Some(5)); +/// assert_eq!(iter.next(), Some(6)); +/// assert_eq!(iter.next(), None); +/// ``` +#[unstable(feature = "iter_chain", reason = "recently added", issue = "125964")] +pub fn chain<A, B>(a: A, b: B) -> Chain<A::IntoIter, B::IntoIter> +where + A: IntoIterator, + B: IntoIterator<Item = A::Item>, +{ + Chain::new(a.into_iter(), b.into_iter()) +} + #[stable(feature = "rust1", since = "1.0.0")] impl<A, B> Iterator for Chain<A, B> where diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index cc514bd914f..05a5f268905 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -41,6 +41,9 @@ pub use self::array_chunks::ArrayChunks; #[unstable(feature = "std_internals", issue = "none")] pub use self::by_ref_sized::ByRefSized; +#[unstable(feature = "iter_chain", reason = "recently added", issue = "125964")] +pub use self::chain::chain; + #[stable(feature = "iter_cloned", since = "1.1.0")] pub use self::cloned::Cloned; diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 44fef3e145b..921c75c85f1 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -428,6 +428,8 @@ pub use self::traits::{ DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum, }; +#[unstable(feature = "iter_chain", reason = "recently added", issue = "125964")] +pub use self::adapters::chain; #[stable(feature = "iter_zip", since = "1.59.0")] pub use self::adapters::zip; #[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 2ddedfa37fe..0d4ca4d5f01 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1569,7 +1569,12 @@ pub(crate) mod builtin { #[rustc_builtin_macro] #[macro_export] #[rustc_diagnostic_item = "assert_macro"] - #[allow_internal_unstable(panic_internals, edition_panic, generic_assert_internals)] + #[allow_internal_unstable( + core_intrinsics, + panic_internals, + edition_panic, + generic_assert_internals + )] macro_rules! assert { ($cond:expr $(,)?) => {{ /* compiler built-in */ }}; ($cond:expr, $($arg:tt)+) => {{ /* compiler built-in */ }}; diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index 026e21586d4..4175d4a3329 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -120,12 +120,8 @@ use crate::slice; /// use std::mem::{self, MaybeUninit}; /// /// let data = { -/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is -/// // safe because the type we are claiming to have initialized here is a -/// // bunch of `MaybeUninit`s, which do not require initialization. -/// let mut data: [MaybeUninit<Vec<u32>>; 1000] = unsafe { -/// MaybeUninit::uninit().assume_init() -/// }; +/// // Create an uninitialized array of `MaybeUninit`. +/// let mut data: [MaybeUninit<Vec<u32>>; 1000] = [const { MaybeUninit::uninit() }; 1000]; /// /// // Dropping a `MaybeUninit` does nothing, so if there is a panic during this loop, /// // we have a memory leak, but there is no memory safety issue. @@ -147,10 +143,8 @@ use crate::slice; /// ``` /// use std::mem::MaybeUninit; /// -/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is -/// // safe because the type we are claiming to have initialized here is a -/// // bunch of `MaybeUninit`s, which do not require initialization. -/// let mut data: [MaybeUninit<String>; 1000] = unsafe { MaybeUninit::uninit().assume_init() }; +/// // Create an uninitialized array of `MaybeUninit`. +/// let mut data: [MaybeUninit<String>; 1000] = [const { MaybeUninit::uninit() }; 1000]; /// // Count the number of elements we have assigned. /// let mut data_len: usize = 0; /// @@ -348,8 +342,7 @@ impl<T> MaybeUninit<T> { #[must_use] #[inline(always)] pub const fn uninit_array<const N: usize>() -> [Self; N] { - // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. - unsafe { MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init() } + [const { MaybeUninit::uninit() }; N] } /// Creates a new `MaybeUninit<T>` in an uninitialized state, with the memory being diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 9362dc87654..129f62fb43d 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -68,6 +68,13 @@ pub mod consts { pub const FRAC_1_SQRT_PI: f128 = 0.564189583547756286948079451560772585844050629328998856844086_f128; + /// 1/sqrt(2π) + #[doc(alias = "FRAC_1_SQRT_TAU")] + #[unstable(feature = "f128", issue = "116909")] + // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + pub const FRAC_1_SQRT_2PI: f128 = + 0.398942280401432677939946059934381868475858631164934657665926_f128; + /// 2/π #[unstable(feature = "f128", issue = "116909")] pub const FRAC_2_PI: f128 = 0.636619772367581343075535053490057448137838582961825794990669_f128; diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index c4d4584544b..7a488cd6bf6 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -67,6 +67,12 @@ pub mod consts { // Also, #[unstable(feature = "more_float_constants", issue = "103883")] pub const FRAC_1_SQRT_PI: f16 = 0.564189583547756286948079451560772586_f16; + /// 1/sqrt(2π) + #[doc(alias = "FRAC_1_SQRT_TAU")] + #[unstable(feature = "f16", issue = "116909")] + // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + pub const FRAC_1_SQRT_2PI: f16 = 0.398942280401432677939946059934381868_f16; + /// 2/π #[unstable(feature = "f16", issue = "116909")] pub const FRAC_2_PI: f16 = 0.636619772367581343075535053490057448_f16; diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 22b24937cbc..9d34d3da9e9 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -327,6 +327,11 @@ pub mod consts { #[unstable(feature = "more_float_constants", issue = "103883")] pub const FRAC_1_SQRT_PI: f32 = 0.564189583547756286948079451560772586_f32; + /// 1/sqrt(2π) + #[doc(alias = "FRAC_1_SQRT_TAU")] + #[unstable(feature = "more_float_constants", issue = "103883")] + pub const FRAC_1_SQRT_2PI: f32 = 0.398942280401432677939946059934381868_f32; + /// 2/π #[stable(feature = "rust1", since = "1.0.0")] pub const FRAC_2_PI: f32 = 0.636619772367581343075535053490057448_f32; diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 34357d1b05a..95f021b2541 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -327,6 +327,11 @@ pub mod consts { #[unstable(feature = "more_float_constants", issue = "103883")] pub const FRAC_1_SQRT_PI: f64 = 0.564189583547756286948079451560772586_f64; + /// 1/sqrt(2π) + #[doc(alias = "FRAC_1_SQRT_TAU")] + #[unstable(feature = "more_float_constants", issue = "103883")] + pub const FRAC_1_SQRT_2PI: f64 = 0.398942280401432677939946059934381868_f64; + /// 2/π #[stable(feature = "rust1", since = "1.0.0")] pub const FRAC_2_PI: f64 = 0.636619772367581343075535053490057448_f64; diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index fcdd983343d..863f0d61df3 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -517,9 +517,13 @@ macro_rules! nonzero_integer { /// ``` /// # use std::num::NonZero; /// # - #[doc = concat!("let n = NonZero::<", stringify!($Int), ">::new(", $leading_zeros_test, ").unwrap();")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::<", stringify!($Int), ">::new(", $leading_zeros_test, ")?;")] /// /// assert_eq!(n.leading_zeros(), 0); + /// # Some(()) + /// # } /// ``` #[stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] #[rustc_const_stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] @@ -545,9 +549,13 @@ macro_rules! nonzero_integer { /// ``` /// # use std::num::NonZero; /// # - #[doc = concat!("let n = NonZero::<", stringify!($Int), ">::new(0b0101000).unwrap();")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let n = NonZero::<", stringify!($Int), ">::new(0b0101000)?;")] /// /// assert_eq!(n.trailing_zeros(), 3); + /// # Some(()) + /// # } /// ``` #[stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] #[rustc_const_stable(feature = "nonzero_leading_trailing_zeros", since = "1.53.0")] @@ -1101,9 +1109,13 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// ``` /// # 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);")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("assert_eq!(NonZero::new(7", stringify!($Int), ")?.ilog2(), 2);")] + #[doc = concat!("assert_eq!(NonZero::new(8", stringify!($Int), ")?.ilog2(), 3);")] + #[doc = concat!("assert_eq!(NonZero::new(9", stringify!($Int), ")?.ilog2(), 3);")] + /// # Some(()) + /// # } /// ``` #[stable(feature = "int_log", since = "1.67.0")] #[rustc_const_stable(feature = "int_log", since = "1.67.0")] @@ -1126,9 +1138,13 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// ``` /// # 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);")] + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("assert_eq!(NonZero::new(99", stringify!($Int), ")?.ilog10(), 1);")] + #[doc = concat!("assert_eq!(NonZero::new(100", stringify!($Int), ")?.ilog10(), 2);")] + #[doc = concat!("assert_eq!(NonZero::new(101", stringify!($Int), ")?.ilog10(), 2);")] + /// # Some(()) + /// # } /// ``` #[stable(feature = "int_log", since = "1.67.0")] #[rustc_const_stable(feature = "int_log", since = "1.67.0")] @@ -1187,10 +1203,16 @@ macro_rules! nonzero_integer_signedness_dependent_methods { /// Basic usage: /// /// ``` - #[doc = concat!("let eight = std::num::NonZero::new(8", stringify!($Int), ").unwrap();")] + /// # use std::num::NonZero; + /// # + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let eight = NonZero::new(8", stringify!($Int), ")?;")] /// assert!(eight.is_power_of_two()); - #[doc = concat!("let ten = std::num::NonZero::new(10", stringify!($Int), ").unwrap();")] + #[doc = concat!("let ten = NonZero::new(10", stringify!($Int), ")?;")] /// assert!(!ten.is_power_of_two()); + /// # Some(()) + /// # } /// ``` #[must_use] #[stable(feature = "nonzero_is_power_of_two", since = "1.59.0")] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 9a527073602..e253cfd2822 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1708,8 +1708,6 @@ impl<T> Option<T> { /// # Examples /// /// ``` - /// #![feature(option_take_if)] - /// /// let mut x = Some(42); /// /// let prev = x.take_if(|v| if *v == 42 { @@ -1726,7 +1724,7 @@ impl<T> Option<T> { /// assert_eq!(prev, Some(43)); /// ``` #[inline] - #[unstable(feature = "option_take_if", issue = "98934")] + #[stable(feature = "option_take_if", since = "CURRENT_RUSTC_VERSION")] pub fn take_if<P>(&mut self, predicate: P) -> Option<T> where P: FnOnce(&mut T) -> bool, diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index d8fc3b7177f..0d2aa3070a1 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -184,7 +184,7 @@ //! requires at least a level of pointer indirection each time a new object is added to the mix //! (and, practically, a heap allocation). //! -//! Although there were other reason as well, this issue of expensive composition is the key thing +//! Although there were other reasons as well, this issue of expensive composition is the key thing //! that drove Rust towards adopting a different model. It is particularly a problem //! when one considers, for example, the implications of composing together the [`Future`]s which //! will eventually make up an asynchronous task (including address-sensitive `async fn` state diff --git a/library/core/src/prelude/common.rs b/library/core/src/prelude/common.rs index afc6817aa1d..2a0331ef7b2 100644 --- a/library/core/src/prelude/common.rs +++ b/library/core/src/prelude/common.rs @@ -14,6 +14,9 @@ pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use crate::mem::drop; +#[stable(feature = "size_of_prelude", since = "CURRENT_RUSTC_VERSION")] +#[doc(no_inline)] +pub use crate::mem::{align_of, align_of_val, size_of, size_of_val}; // Re-exported types and traits #[stable(feature = "core_prelude", since = "1.4.0")] diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 8e3447d0b1b..6661f6ee78b 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -415,7 +415,7 @@ use crate::intrinsics; use crate::marker::FnPtr; use crate::ub_checks; -use crate::mem::{self, align_of, size_of, MaybeUninit}; +use crate::mem::{self, MaybeUninit}; mod alignment; #[unstable(feature = "ptr_alignment_type", issue = "102070")] diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index 29a12f106c5..3f4305866e6 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -1,7 +1,6 @@ //! Free functions to create `&[T]` and `&mut [T]`. use crate::array; -use crate::mem::{align_of, size_of}; use crate::ops::Range; use crate::ptr; use crate::ub_checks; diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 232ec589093..482bd19705c 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1296,7 +1296,6 @@ impl<T> AtomicPtr<T> { #[cfg(target_has_atomic_equal_alignment = "ptr")] #[unstable(feature = "atomic_from_mut", issue = "76314")] pub fn from_mut(v: &mut *mut T) -> &mut Self { - use crate::mem::align_of; let [] = [(); align_of::<AtomicPtr<()>>() - align_of::<*mut ()>()]; // SAFETY: // - the mutable reference guarantees unique ownership. @@ -2286,7 +2285,6 @@ macro_rules! atomic_int { #[$cfg_align] #[unstable(feature = "atomic_from_mut", issue = "76314")] pub fn from_mut(v: &mut $int_type) -> &mut Self { - use crate::mem::align_of; let [] = [(); align_of::<Self>() - align_of::<$int_type>()]; // SAFETY: // - the mutable reference guarantees unique ownership. @@ -2354,7 +2352,6 @@ macro_rules! atomic_int { #[$cfg_align] #[unstable(feature = "atomic_from_mut", issue = "76314")] pub fn from_mut_slice(v: &mut [$int_type]) -> &mut [Self] { - use crate::mem::align_of; let [] = [(); align_of::<Self>() - align_of::<$int_type>()]; // SAFETY: // - the mutable reference guarantees unique ownership. diff --git a/library/core/tests/iter/adapters/chain.rs b/library/core/tests/iter/adapters/chain.rs index b2429588de1..c93510df524 100644 --- a/library/core/tests/iter/adapters/chain.rs +++ b/library/core/tests/iter/adapters/chain.rs @@ -3,6 +3,14 @@ use core::iter::*; use core::num::NonZero; #[test] +fn test_chain() { + let xs = [0, 1, 2, 3, 4, 5]; + let ys = [30, 40, 50, 60]; + let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; + assert_eq!(Vec::from_iter(chain(xs, ys)), expected); +} + +#[test] fn test_iterator_chain() { let xs = [0, 1, 2, 3, 4, 5]; let ys = [30, 40, 50, 60]; diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index e0f82c91663..f632883b563 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -75,6 +75,7 @@ #![feature(ip)] #![feature(iter_advance_by)] #![feature(iter_array_chunks)] +#![feature(iter_chain)] #![feature(iter_collect_into)] #![feature(iter_partition_in_place)] #![feature(iter_intersperse)] @@ -111,7 +112,6 @@ #![feature(const_slice_from_ref)] #![feature(waker_getters)] #![feature(error_generic_member_access)] -#![feature(error_in_core)] #![feature(trait_upcasting)] #![feature(is_ascii_octdigit)] #![feature(get_many_mut)] diff --git a/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs index 0f1719206c9..cbffbc564cf 100644 --- a/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs +++ b/library/portable-simd/crates/core_simd/src/simd/ptr/const_ptr.rs @@ -96,7 +96,7 @@ where fn cast<U>(self) -> Self::CastPtr<U> { // SimdElement currently requires zero-sized metadata, so this should never fail. // If this ever changes, `simd_cast_ptr` should produce a post-mono error. - use core::{mem::size_of, ptr::Pointee}; + use core::ptr::Pointee; assert_eq!(size_of::<<T as Pointee>::Metadata>(), 0); assert_eq!(size_of::<<U as Pointee>::Metadata>(), 0); diff --git a/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs index 7ba996d149c..6bc6ca3ac42 100644 --- a/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs +++ b/library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs @@ -93,7 +93,7 @@ where fn cast<U>(self) -> Self::CastPtr<U> { // SimdElement currently requires zero-sized metadata, so this should never fail. // If this ever changes, `simd_cast_ptr` should produce a post-mono error. - use core::{mem::size_of, ptr::Pointee}; + use core::ptr::Pointee; assert_eq!(size_of::<<T as Pointee>::Metadata>(), 0); assert_eq!(size_of::<<U as Pointee>::Metadata>(), 0); diff --git a/library/proc_macro/src/bridge/fxhash.rs b/library/proc_macro/src/bridge/fxhash.rs index f9f74c63fc4..9fb79eabd05 100644 --- a/library/proc_macro/src/bridge/fxhash.rs +++ b/library/proc_macro/src/bridge/fxhash.rs @@ -7,7 +7,6 @@ use std::collections::HashMap; use std::hash::BuildHasherDefault; use std::hash::Hasher; -use std::mem::size_of; use std::ops::BitXor; /// Type alias for a hashmap using the `fx` hash algorithm. diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 79a504c5a5e..68bba5c2be1 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -34,10 +34,10 @@ addr2line = { version = "0.22.0", optional = true, default-features = false } libc = { version = "0.2.153", default-features = false, features = ['rustc-dep-of-std'], public = true } [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'] } +object = { version = "0.36.0", default-features = false, optional = true, features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] } [target.'cfg(target_os = "aix")'.dependencies] -object = { version = "0.32.0", default-features = false, optional = true, features = ['read_core', 'xcoff', 'unaligned', 'archive'] } +object = { version = "0.36.0", default-features = false, optional = true, features = ['read_core', 'xcoff', 'unaligned', 'archive'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 5039f0b6bb2..fcd1c307b5a 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1218,7 +1218,7 @@ where /// will cause the map to produce seemingly random results. Higher-level and /// more foolproof APIs like `entry` should be preferred when possible. /// - /// In particular, the hash used to initialized the raw entry must still be + /// In particular, the hash used to initialize the raw entry must still be /// consistent with the hash of the key that is ultimately stored in the entry. /// This is because implementations of HashMap may need to recompute hashes /// when resizing, at which point only the keys are available. diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 9dd3d7d3fa1..f6b9de26c1c 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -533,6 +533,25 @@ impl OsString { unsafe { Box::from_raw(rw) } } + /// Consumes and leaks the `OsString`, returning a mutable reference to the contents, + /// `&'a mut OsStr`. + /// + /// The caller has free choice over the returned lifetime, including 'static. + /// Indeed, this function is ideally used for data that lives for the remainder of + /// the program’s life, as dropping the returned reference will cause a memory leak. + /// + /// It does not reallocate or shrink the `OsString`, so the leaked allocation may include + /// unused capacity that is not part of the returned slice. If you want to discard excess + /// capacity, call [`into_boxed_os_str`], and then [`Box::leak`] instead. + /// However, keep in mind that trimming the capacity may result in a reallocation and copy. + /// + /// [`into_boxed_os_str`]: Self::into_boxed_os_str + #[unstable(feature = "os_string_pathbuf_leak", issue = "125965")] + #[inline] + pub fn leak<'a>(self) -> &'a mut OsStr { + OsStr::from_inner_mut(self.inner.leak()) + } + /// Part of a hack to make PathBuf::push/pop more efficient. #[inline] pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec<u8> { diff --git a/library/std/src/ffi/os_str/tests.rs b/library/std/src/ffi/os_str/tests.rs index b020e05eaab..5b39b9e34d8 100644 --- a/library/std/src/ffi/os_str/tests.rs +++ b/library/std/src/ffi/os_str/tests.rs @@ -24,6 +24,15 @@ fn test_os_string_clear() { } #[test] +fn test_os_string_leak() { + let os_string = OsString::from("have a cake"); + let (len, cap) = (os_string.len(), os_string.capacity()); + let leaked = os_string.leak(); + assert_eq!(leaked.as_encoded_bytes(), b"have a cake"); + unsafe { drop(String::from_raw_parts(leaked as *mut OsStr as _, len, cap)) } +} + +#[test] fn test_os_string_capacity() { let os_string = OsString::with_capacity(0); assert_eq!(0, os_string.capacity()); diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index 6f8d5e37775..c9d3934ad70 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -104,7 +104,6 @@ use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage}; use core::marker::PhantomData; -use core::mem::{align_of, size_of}; use core::ptr::{self, NonNull}; // The 2 least-significant bits are used as tag. diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index c8968b74b12..9aee2bb5e1c 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -1190,9 +1190,8 @@ pub trait IsTerminal: crate::sealed::Sealed { /// /// - If you run this example by piping some text to it, e.g. `echo "foo" | path/to/executable` /// it will print: `Hello foo`. - /// - If you instead run the example interactively by running the executable directly, it will - /// panic with the message "Expected input to be piped to the process". - /// + /// - If you instead run the example interactively by running `path/to/executable` directly, it will + /// prompt for input. /// /// [changes]: io#platform-specific-behavior /// [`Stdin`]: crate::io::Stdin diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 9d6576fa841..1c226f9f08f 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -324,7 +324,6 @@ #![feature(core_io_borrowed_buf)] #![feature(duration_constants)] #![feature(error_generic_member_access)] -#![feature(error_in_core)] #![feature(error_iter)] #![feature(exact_size_is_empty)] #![feature(exclusive_wrapper)] diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs index 0597fdcbd72..fe8e2be9372 100644 --- a/library/std/src/os/unix/net/ancillary.rs +++ b/library/std/src/os/unix/net/ancillary.rs @@ -3,7 +3,7 @@ use super::{sockaddr_un, SocketAddr}; use crate::io::{self, IoSlice, IoSliceMut}; use crate::marker::PhantomData; -use crate::mem::{size_of, zeroed}; +use crate::mem::zeroed; use crate::os::unix::io::RawFd; use crate::path::Path; use crate::ptr::{eq, read_unaligned}; diff --git a/library/std/src/path.rs b/library/std/src/path.rs index f4e1e2a38c1..adbcdcd2e67 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1226,6 +1226,25 @@ impl PathBuf { self } + /// Consumes and leaks the `PathBuf`, returning a mutable reference to the contents, + /// `&'a mut Path`. + /// + /// The caller has free choice over the returned lifetime, including 'static. + /// Indeed, this function is ideally used for data that lives for the remainder of + /// the program’s life, as dropping the returned reference will cause a memory leak. + /// + /// It does not reallocate or shrink the `PathBuf`, so the leaked allocation may include + /// unused capacity that is not part of the returned slice. If you want to discard excess + /// capacity, call [`into_boxed_path`], and then [`Box::leak`] instead. + /// However, keep in mind that trimming the capacity may result in a reallocation and copy. + /// + /// [`into_boxed_path`]: Self::into_boxed_path + #[unstable(feature = "os_string_pathbuf_leak", issue = "125965")] + #[inline] + pub fn leak<'a>(self) -> &'a mut Path { + Path::from_inner_mut(self.inner.leak()) + } + /// Extends `self` with `path`. /// /// If `path` is absolute, it replaces the current path. diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index 2d8e50d1f88..92702b395df 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -127,6 +127,16 @@ fn into() { } #[test] +fn test_pathbuf_leak() { + let string = "/have/a/cake".to_owned(); + let (len, cap) = (string.len(), string.capacity()); + let buf = PathBuf::from(string); + let leaked = buf.leak(); + assert_eq!(leaked.as_os_str().as_encoded_bytes(), b"/have/a/cake"); + unsafe { drop(String::from_raw_parts(leaked.as_mut_os_str() as *mut OsStr as _, len, cap)) } +} + +#[test] #[cfg(unix)] pub fn test_decompositions_unix() { t!("", diff --git a/library/std/src/prelude/common.rs b/library/std/src/prelude/common.rs index 01936734d75..ceee3e33c3e 100644 --- a/library/std/src/prelude/common.rs +++ b/library/std/src/prelude/common.rs @@ -14,6 +14,9 @@ pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] pub use crate::mem::drop; +#[stable(feature = "size_of_prelude", since = "CURRENT_RUSTC_VERSION")] +#[doc(no_inline)] +pub use crate::mem::{align_of, align_of_val, size_of, size_of_val}; // Re-exported types and traits #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index 0bdbab716ad..2d4639342bf 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -36,6 +36,10 @@ //! operations for both destructors and overloading `()`. //! * <code>[std::mem]::[drop]</code>, a convenience function for explicitly //! dropping a value. +//! * <code>[std::mem]::{[size_of], [size_of_val]}</code>, to get the size of +//! a type or value. +//! * <code>[std::mem]::{[align_of], [align_of_val]}</code>, to get the +//! alignment of a type or value. //! * <code>[std::boxed]::[Box]</code>, a way to allocate values on the heap. //! * <code>[std::borrow]::[ToOwned]</code>, the conversion trait that defines //! [`to_owned`], the generic method for creating an owned type from a diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index d3bb3bfdff9..7a2eed93dd4 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -29,34 +29,26 @@ union Data<T, F> { /// # Examples /// /// Initialize static variables with `LazyLock`. -/// /// ``` -/// use std::collections::HashMap; -/// /// use std::sync::LazyLock; /// -/// static HASHMAP: LazyLock<HashMap<i32, String>> = LazyLock::new(|| { -/// println!("initializing"); -/// let mut m = HashMap::new(); -/// m.insert(13, "Spica".to_string()); -/// m.insert(74, "Hoyten".to_string()); -/// m +/// // n.b. static items do not call [`Drop`] on program termination, so this won't be deallocated. +/// // this is fine, as the OS can deallocate the terminated program faster than we can free memory +/// // but tools like valgrind might report "memory leaks" as it isn't obvious this is intentional. +/// static DEEP_THOUGHT: LazyLock<String> = LazyLock::new(|| { +/// # mod another_crate { +/// # pub fn great_question() -> String { "42".to_string() } +/// # } +/// // M3 Ultra takes about 16 million years in --release config +/// another_crate::great_question() /// }); /// -/// fn main() { -/// println!("ready"); -/// std::thread::spawn(|| { -/// println!("{:?}", HASHMAP.get(&13)); -/// }).join().unwrap(); -/// println!("{:?}", HASHMAP.get(&74)); -/// -/// // Prints: -/// // ready -/// // initializing -/// // Some("Spica") -/// // Some("Hoyten") -/// } +/// // The `String` is built, stored in the `LazyLock`, and returned as `&String`. +/// let _ = &*DEEP_THOUGHT; +/// // The `String` is retrieved from the `LazyLock` and returned as `&String`. +/// let _ = &*DEEP_THOUGHT; /// ``` +/// /// Initialize fields with `LazyLock`. /// ``` /// use std::sync::LazyLock; diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index fb7d601b094..70e8f5f90c6 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -136,7 +136,10 @@ //! - [`Once`]: Used for a thread-safe, one-time global initialization routine //! //! - [`OnceLock`]: Used for thread-safe, one-time initialization of a -//! global variable. +//! variable, with potentially different initializers based on the caller. +//! +//! - [`LazyLock`]: Used for thread-safe, one-time initialization of a +//! variable, using one nullary initializer function provided at creation. //! //! - [`RwLock`]: Provides a mutual exclusion mechanism which allows //! multiple readers at the same time, while allowing only one diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index fc830bacced..f52b9e52c54 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -5,50 +5,20 @@ use crate::mem::MaybeUninit; use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::sync::Once; -/// A synchronization primitive which can be written to only once. +/// A synchronization primitive which can nominally be written to only once. /// /// This type is a thread-safe [`OnceCell`], and can be used in statics. +/// In many simple cases, you can use [`LazyLock<T, F>`] instead to get the benefits of this type +/// with less effort: `LazyLock<T, F>` "looks like" `&T` because it initializes with `F` on deref! +/// Where OnceLock shines is when LazyLock is too simple to support a given case, as LazyLock +/// doesn't allow additional inputs to its function after you call [`LazyLock::new(|| ...)`]. /// /// [`OnceCell`]: crate::cell::OnceCell +/// [`LazyLock<T, F>`]: crate::sync::LazyLock +/// [`LazyLock::new(|| ...)`]: crate::sync::LazyLock::new /// /// # Examples /// -/// Using `OnceLock` to store a function’s previously computed value (a.k.a. -/// ‘lazy static’ or ‘memoizing’): -/// -/// ``` -/// use std::sync::OnceLock; -/// -/// struct DeepThought { -/// answer: String, -/// } -/// -/// impl DeepThought { -/// # fn great_question() -> String { -/// # "42".to_string() -/// # } -/// # -/// fn new() -> Self { -/// Self { -/// // M3 Ultra takes about 16 million years in --release config -/// answer: Self::great_question(), -/// } -/// } -/// } -/// -/// fn computation() -> &'static DeepThought { -/// // n.b. static items do not call [`Drop`] on program termination, so if -/// // [`DeepThought`] impls Drop, that will not be used for this instance. -/// static COMPUTATION: OnceLock<DeepThought> = OnceLock::new(); -/// COMPUTATION.get_or_init(|| DeepThought::new()) -/// } -/// -/// // The `DeepThought` is built, stored in the `OnceLock`, and returned. -/// let _ = computation().answer; -/// // The `DeepThought` is retrieved from the `OnceLock` and returned. -/// let _ = computation().answer; -/// ``` -/// /// Writing to a `OnceLock` from a separate thread: /// /// ``` @@ -73,6 +43,55 @@ use crate::sync::Once; /// Some(&12345), /// ); /// ``` +/// +/// You can use `OnceLock` to implement a type that requires "append-only" logic: +/// +/// ``` +/// use std::sync::{OnceLock, atomic::{AtomicU32, Ordering}}; +/// use std::thread; +/// +/// struct OnceList<T> { +/// data: OnceLock<T>, +/// next: OnceLock<Box<OnceList<T>>>, +/// } +/// impl<T> OnceList<T> { +/// const fn new() -> OnceList<T> { +/// OnceList { data: OnceLock::new(), next: OnceLock::new() } +/// } +/// fn push(&self, value: T) { +/// // FIXME: this impl is concise, but is also slow for long lists or many threads. +/// // as an exercise, consider how you might improve on it while preserving the behavior +/// if let Err(value) = self.data.set(value) { +/// let next = self.next.get_or_init(|| Box::new(OnceList::new())); +/// next.push(value) +/// }; +/// } +/// fn contains(&self, example: &T) -> bool +/// where +/// T: PartialEq, +/// { +/// self.data.get().map(|item| item == example).filter(|v| *v).unwrap_or_else(|| { +/// self.next.get().map(|next| next.contains(example)).unwrap_or(false) +/// }) +/// } +/// } +/// +/// // Let's exercise this new Sync append-only list by doing a little counting +/// static LIST: OnceList<u32> = OnceList::new(); +/// static COUNTER: AtomicU32 = AtomicU32::new(0); +/// +/// let vec = (0..thread::available_parallelism().unwrap().get()).map(|_| thread::spawn(|| { +/// while let i @ 0..=1000 = COUNTER.fetch_add(1, Ordering::Relaxed) { +/// LIST.push(i); +/// } +/// })).collect::<Vec<thread::JoinHandle<_>>>(); +/// vec.into_iter().for_each(|handle| handle.join().unwrap()); +/// +/// for i in 0..=1000 { +/// assert!(LIST.contains(&i)); +/// } +/// +/// ``` #[stable(feature = "once_cell", since = "1.70.0")] pub struct OnceLock<T> { once: Once, diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index 18b969bca85..f7c6b0877aa 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -177,6 +177,11 @@ impl Buf { } #[inline] + pub fn leak<'a>(self) -> &'a mut Slice { + unsafe { mem::transmute(self.inner.leak()) } + } + + #[inline] pub fn into_box(self) -> Box<Slice> { unsafe { mem::transmute(self.inner.into_boxed_slice()) } } diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index b3ceb55802d..dfff4dd4fb0 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -139,6 +139,11 @@ impl Buf { } #[inline] + pub fn leak<'a>(self) -> &'a mut Slice { + unsafe { mem::transmute(self.inner.leak()) } + } + + #[inline] pub fn into_box(self) -> Box<Slice> { unsafe { mem::transmute(self.inner.into_box()) } } diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/pal/sgx/thread.rs index 7d271e6d2b6..446cdd18b7e 100644 --- a/library/std/src/sys/pal/sgx/thread.rs +++ b/library/std/src/sys/pal/sgx/thread.rs @@ -15,7 +15,7 @@ pub use self::task_queue::JoinNotifier; mod task_queue { use super::wait_notify; - use crate::sync::{Mutex, MutexGuard, Once}; + use crate::sync::{Mutex, MutexGuard}; pub type JoinHandle = wait_notify::Waiter; @@ -28,12 +28,12 @@ mod task_queue { } pub(super) struct Task { - p: Box<dyn FnOnce()>, + p: Box<dyn FnOnce() + Send>, done: JoinNotifier, } impl Task { - pub(super) fn new(p: Box<dyn FnOnce()>) -> (Task, JoinHandle) { + pub(super) fn new(p: Box<dyn FnOnce() + Send>) -> (Task, JoinHandle) { let (done, recv) = wait_notify::new(); let done = JoinNotifier(Some(done)); (Task { p, done }, recv) @@ -46,17 +46,11 @@ mod task_queue { } #[cfg_attr(test, linkage = "available_externally")] - #[export_name = "_ZN16__rust_internals3std3sys3sgx6thread15TASK_QUEUE_INITE"] - static TASK_QUEUE_INIT: Once = Once::new(); - #[cfg_attr(test, linkage = "available_externally")] #[export_name = "_ZN16__rust_internals3std3sys3sgx6thread10TASK_QUEUEE"] - static mut TASK_QUEUE: Option<Mutex<Vec<Task>>> = None; + static TASK_QUEUE: Mutex<Vec<Task>> = Mutex::new(Vec::new()); pub(super) fn lock() -> MutexGuard<'static, Vec<Task>> { - unsafe { - TASK_QUEUE_INIT.call_once(|| TASK_QUEUE = Some(Default::default())); - TASK_QUEUE.as_ref().unwrap().lock().unwrap() - } + TASK_QUEUE.lock().unwrap() } } @@ -101,7 +95,7 @@ pub mod wait_notify { impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> { + pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce() + Send>) -> io::Result<Thread> { let mut queue_lock = task_queue::lock(); unsafe { usercalls::launch_thread()? }; let (task, handle) = task_queue::Task::new(p); diff --git a/library/std/src/sys/pal/uefi/thread.rs b/library/std/src/sys/pal/uefi/thread.rs index edc736978a1..7d4006ff4b2 100644 --- a/library/std/src/sys/pal/uefi/thread.rs +++ b/library/std/src/sys/pal/uefi/thread.rs @@ -7,7 +7,7 @@ use crate::time::Duration; pub struct Thread(!); -pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; +pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index fbbd40bfb79..56a0f8e39c4 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -1481,29 +1481,33 @@ impl FromRawFd for File { impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[cfg(any( - target_os = "linux", - target_os = "netbsd", - target_os = "illumos", - target_os = "solaris" - ))] + #[cfg(any(target_os = "linux", target_os = "illumos", target_os = "solaris"))] fn get_path(fd: c_int) -> Option<PathBuf> { let mut p = PathBuf::from("/proc/self/fd"); p.push(&fd.to_string()); readlink(&p).ok() } - #[cfg(target_vendor = "apple")] + #[cfg(any(target_vendor = "apple", target_os = "netbsd"))] fn get_path(fd: c_int) -> Option<PathBuf> { // FIXME: The use of PATH_MAX is generally not encouraged, but it - // is inevitable in this case because Apple targets define `fcntl` + // is inevitable in this case because Apple targets and NetBSD 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]; let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) }; if n == -1 { - return None; + cfg_if::cfg_if! { + if #[cfg(target_os = "netbsd")] { + // fallback to procfs as last resort + let mut p = PathBuf::from("/proc/self/fd"); + p.push(&fd.to_string()); + return readlink(&p).ok(); + } else { + return None; + } + } } let l = buf.iter().position(|&c| c == 0).unwrap(); buf.truncate(l as usize); @@ -1557,6 +1561,8 @@ impl fmt::Debug for File { target_os = "netbsd", target_os = "openbsd", target_os = "vxworks", + target_os = "solaris", + target_os = "illumos", target_vendor = "apple", ))] fn get_mode(fd: c_int) -> Option<(bool, bool)> { @@ -1579,6 +1585,8 @@ impl fmt::Debug for File { target_os = "netbsd", target_os = "openbsd", target_os = "vxworks", + target_os = "solaris", + target_os = "illumos", target_vendor = "apple", )))] fn get_mode(_fd: c_int) -> Option<(bool, bool)> { @@ -1910,8 +1918,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { // The code below ensures that `FreeOnDrop` is never a null pointer unsafe { // `copyfile_state_free` returns -1 if the `to` or `from` files - // cannot be closed. However, this is not considered this an - // error. + // cannot be closed. However, this is not considered an error. libc::copyfile_state_free(self.0); } } diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index b5c7d30da7b..2e71ceceb58 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -462,21 +462,21 @@ pub fn current_exe() -> io::Result<PathBuf> { #[cfg(target_os = "haiku")] pub fn current_exe() -> io::Result<PathBuf> { + let mut name = vec![0; libc::PATH_MAX as usize]; unsafe { - let mut info: mem::MaybeUninit<libc::image_info> = mem::MaybeUninit::uninit(); - let mut cookie: i32 = 0; - // the executable can be found at team id 0 - let result = libc::_get_next_image_info( - 0, - &mut cookie, - info.as_mut_ptr(), - mem::size_of::<libc::image_info>(), + let result = libc::find_path( + crate::ptr::null_mut(), + libc::path_base_directory::B_FIND_PATH_IMAGE_PATH, + crate::ptr::null_mut(), + name.as_mut_ptr(), + name.len(), ); - if result != 0 { + if result != libc::B_OK { use crate::io::ErrorKind; Err(io::const_io_error!(ErrorKind::Uncategorized, "Error getting executable path")) } else { - let name = CStr::from_ptr((*info.as_ptr()).name.as_ptr()).to_bytes(); + // find_path adds the null terminator. + let name = CStr::from_ptr(name.as_ptr()).to_bytes(); Ok(PathBuf::from(OsStr::from_bytes(name))) } } diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index e2fca8c7e63..72bda90a9ba 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -1053,6 +1053,10 @@ fn signal_string(signal: i32) -> &'static str { libc::SIGINFO => " (SIGINFO)", #[cfg(target_os = "hurd")] libc::SIGLOST => " (SIGLOST)", + #[cfg(target_os = "freebsd")] + libc::SIGTHR => " (SIGTHR)", + #[cfg(target_os = "freebsd")] + libc::SIGLIBRT => " (SIGLIBRT)", _ => "", } } diff --git a/library/std/src/sys/pal/unsupported/thread.rs b/library/std/src/sys/pal/unsupported/thread.rs index ea939247199..89f8bad7026 100644 --- a/library/std/src/sys/pal/unsupported/thread.rs +++ b/library/std/src/sys/pal/unsupported/thread.rs @@ -6,7 +6,7 @@ use crate::time::Duration; pub struct Thread(!); -pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; +pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs index d45fb28b67e..975eef2451f 100644 --- a/library/std/src/sys/pal/wasi/thread.rs +++ b/library/std/src/sys/pal/wasi/thread.rs @@ -66,7 +66,7 @@ cfg_if::cfg_if! { } } -pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; +pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements diff --git a/library/std/src/sys/pal/wasm/atomics/thread.rs b/library/std/src/sys/pal/wasm/atomics/thread.rs index 49f936f1449..484bd08495e 100644 --- a/library/std/src/sys/pal/wasm/atomics/thread.rs +++ b/library/std/src/sys/pal/wasm/atomics/thread.rs @@ -6,7 +6,7 @@ use crate::time::Duration; pub struct Thread(!); -pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; +pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements diff --git a/library/std/src/sys/pal/windows/api.rs b/library/std/src/sys/pal/windows/api.rs index 555ad581b85..17a0e47ad59 100644 --- a/library/std/src/sys/pal/windows/api.rs +++ b/library/std/src/sys/pal/windows/api.rs @@ -251,3 +251,39 @@ pub fn get_last_error() -> WinError { pub struct WinError { pub code: u32, } +impl WinError { + const fn new(code: u32) -> Self { + Self { code } + } +} + +// Error code constants. +// The constant names should be the same as the winapi constants except for the leading `ERROR_`. +// Due to the sheer number of codes, error codes should only be added here on an as-needed basis. +// However, they should never be removed as the assumption is they may be useful again in the future. +#[allow(unused)] +impl WinError { + /// Success is not an error. + /// Some Windows APIs do use this to distinguish between a zero return and an error return + /// but we should never return this to users as an error. + pub const SUCCESS: Self = Self::new(c::ERROR_SUCCESS); + // tidy-alphabetical-start + pub const ACCESS_DENIED: Self = Self::new(c::ERROR_ACCESS_DENIED); + pub const ALREADY_EXISTS: Self = Self::new(c::ERROR_ALREADY_EXISTS); + pub const CANT_ACCESS_FILE: Self = Self::new(c::ERROR_CANT_ACCESS_FILE); + pub const DELETE_PENDING: Self = Self::new(c::ERROR_DELETE_PENDING); + pub const DIRECTORY: Self = Self::new(c::ERROR_DIRECTORY); + pub const FILE_NOT_FOUND: Self = Self::new(c::ERROR_FILE_NOT_FOUND); + pub const INSUFFICIENT_BUFFER: Self = Self::new(c::ERROR_INSUFFICIENT_BUFFER); + pub const INVALID_FUNCTION: Self = Self::new(c::ERROR_INVALID_FUNCTION); + pub const INVALID_HANDLE: Self = Self::new(c::ERROR_INVALID_HANDLE); + pub const INVALID_PARAMETER: Self = Self::new(c::ERROR_INVALID_PARAMETER); + pub const NO_MORE_FILES: Self = Self::new(c::ERROR_NO_MORE_FILES); + pub const NOT_FOUND: Self = Self::new(c::ERROR_NOT_FOUND); + pub const NOT_SUPPORTED: Self = Self::new(c::ERROR_NOT_SUPPORTED); + pub const OPERATION_ABORTED: Self = Self::new(c::ERROR_OPERATION_ABORTED); + pub const PATH_NOT_FOUND: Self = Self::new(c::ERROR_PATH_NOT_FOUND); + pub const SHARING_VIOLATION: Self = Self::new(c::ERROR_SHARING_VIOLATION); + pub const TIMEOUT: Self = Self::new(c::ERROR_TIMEOUT); + // tidy-alphabetical-end +} diff --git a/library/std/src/sys/pal/windows/c/README.md b/library/std/src/sys/pal/windows/c/README.md index d458e55efbc..efefc5faba7 100644 --- a/library/std/src/sys/pal/windows/c/README.md +++ b/library/std/src/sys/pal/windows/c/README.md @@ -3,7 +3,7 @@ be edited manually. To add bindings, edit `bindings.txt` then regenerate using the following command: - ./x run generate-windows-sys && ./x fmt library/std + ./x run generate-windows-sys && ./x fmt If you need to override generated functions or types then add them to `library/std/src/sys/pal/windows/c.rs`. diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index e92c5e80eac..629ff114b5a 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -18,7 +18,8 @@ use crate::sys::{c, cvt, Align8}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::thread; -use super::{api, to_u16s, IoResult}; +use super::api::{self, WinError}; +use super::{to_u16s, IoResult}; use crate::sys::path::maybe_verbatim; pub struct File { @@ -130,10 +131,11 @@ impl Iterator for ReadDir { let mut wfd = mem::zeroed(); loop { if c::FindNextFileW(self.handle.0, &mut wfd) == 0 { - if api::get_last_error().code == c::ERROR_NO_MORE_FILES { - return None; - } else { - return Some(Err(Error::last_os_error())); + match api::get_last_error() { + WinError::NO_MORE_FILES => return None, + WinError { code } => { + return Some(Err(Error::from_raw_os_error(code as i32))); + } } } if let Some(e) = DirEntry::new(&self.root, &wfd) { @@ -244,8 +246,6 @@ impl OpenOptions { } fn get_access_mode(&self) -> io::Result<c::DWORD> { - const ERROR_INVALID_PARAMETER: i32 = 87; - match (self.read, self.write, self.append, self.access_mode) { (.., Some(mode)) => Ok(mode), (true, false, false, None) => Ok(c::GENERIC_READ), @@ -255,23 +255,23 @@ impl OpenOptions { (true, _, true, None) => { Ok(c::GENERIC_READ | (c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA)) } - (false, false, false, None) => Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER)), + (false, false, false, None) => { + Err(Error::from_raw_os_error(c::ERROR_INVALID_PARAMETER as i32)) + } } } fn get_creation_mode(&self) -> io::Result<c::DWORD> { - const ERROR_INVALID_PARAMETER: i32 = 87; - match (self.write, self.append) { (true, false) => {} (false, false) => { if self.truncate || self.create || self.create_new { - return Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER)); + return Err(Error::from_raw_os_error(c::ERROR_INVALID_PARAMETER as i32)); } } (_, true) => { if self.truncate && !self.create_new { - return Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER)); + return Err(Error::from_raw_os_error(c::ERROR_INVALID_PARAMETER as i32)); } } } @@ -315,7 +315,7 @@ impl File { // Manual truncation. See #115745. if opts.truncate && creation == c::OPEN_ALWAYS - && unsafe { c::GetLastError() } == c::ERROR_ALREADY_EXISTS + && api::get_last_error() == WinError::ALREADY_EXISTS { unsafe { // This originally used `FileAllocationInfo` instead of @@ -845,7 +845,7 @@ fn open_link_no_reparse(parent: &File, name: &[u16], access: u32) -> io::Result< // We make a special exception for `STATUS_DELETE_PENDING` because // otherwise this will be mapped to `ERROR_ACCESS_DENIED` which is // very unhelpful. - Err(io::Error::from_raw_os_error(c::ERROR_DELETE_PENDING as _)) + Err(io::Error::from_raw_os_error(c::ERROR_DELETE_PENDING as i32)) } else if status == c::STATUS_INVALID_PARAMETER && ATTRIBUTES.load(Ordering::Relaxed) == c::OBJ_DONT_REPARSE { @@ -1097,7 +1097,7 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> { // // See issue #120040: https://github.com/rust-lang/rust/issues/120040. let last_error = api::get_last_error(); - if last_error.code == c::ERROR_FILE_NOT_FOUND { + if last_error == WinError::FILE_NOT_FOUND { return Ok(ReadDir { handle: FindNextFileHandle(find_handle), root: Arc::new(root), diff --git a/library/std/src/sys/pal/windows/futex.rs b/library/std/src/sys/pal/windows/futex.rs index bc19c402d9c..08b7fe300dc 100644 --- a/library/std/src/sys/pal/windows/futex.rs +++ b/library/std/src/sys/pal/windows/futex.rs @@ -1,4 +1,4 @@ -use super::api; +use super::api::{self, WinError}; use crate::sys::c; use crate::sys::dur2timeout; use core::ffi::c_void; @@ -72,7 +72,7 @@ pub fn wake_by_address_all<T>(address: &T) { pub fn futex_wait<W: Waitable>(futex: &W::Atomic, expected: W, timeout: Option<Duration>) -> bool { // return false only on timeout - wait_on_address(futex, expected, timeout) || api::get_last_error().code != c::ERROR_TIMEOUT + wait_on_address(futex, expected, timeout) || api::get_last_error() != WinError::TIMEOUT } pub fn futex_wake<T>(futex: &T) -> bool { diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 483b8b0072c..62199c16bfe 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -17,7 +17,8 @@ use crate::ptr; use crate::slice; use crate::sys::{c, cvt}; -use super::{api, to_u16s}; +use super::api::{self, WinError}; +use super::to_u16s; pub fn errno() -> i32 { api::get_last_error().code as i32 @@ -333,7 +334,7 @@ fn home_dir_crt() -> Option<PathBuf> { buf, &mut sz, ) { - 0 if api::get_last_error().code != c::ERROR_INSUFFICIENT_BUFFER => 0, + 0 if api::get_last_error() != WinError::INSUFFICIENT_BUFFER => 0, 0 => sz, _ => sz - 1, // sz includes the null terminator } @@ -358,7 +359,7 @@ fn home_dir_crt() -> Option<PathBuf> { super::fill_utf16_buf( |buf, mut sz| { match c::GetUserProfileDirectoryW(token, buf, &mut sz) { - 0 if api::get_last_error().code != c::ERROR_INSUFFICIENT_BUFFER => 0, + 0 if api::get_last_error() != WinError::INSUFFICIENT_BUFFER => 0, 0 => sz, _ => sz - 1, // sz includes the null terminator } diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index dfa938d4d57..67ef3ca82da 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -12,6 +12,7 @@ use crate::sys::c; use crate::sys::fs::{File, OpenOptions}; use crate::sys::handle::Handle; use crate::sys::hashmap_random_keys; +use crate::sys::pal::windows::api::{self, WinError}; use crate::sys_common::{FromInner, IntoInner}; //////////////////////////////////////////////////////////////////////////////// @@ -124,20 +125,19 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res // testing strategy // For more info, see https://github.com/rust-lang/rust/pull/37677. if handle == c::INVALID_HANDLE_VALUE { - let err = io::Error::last_os_error(); - let raw_os_err = err.raw_os_error(); + let error = api::get_last_error(); if tries < 10 { - if raw_os_err == Some(c::ERROR_ACCESS_DENIED as i32) { + if error == WinError::ACCESS_DENIED { continue; } else if reject_remote_clients_flag != 0 - && raw_os_err == Some(c::ERROR_INVALID_PARAMETER as i32) + && error == WinError::INVALID_PARAMETER { reject_remote_clients_flag = 0; tries -= 1; continue; } } - return Err(err); + return Err(io::Error::from_raw_os_error(error.code as i32)); } ours = Handle::from_raw_handle(handle); break; diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs index e4ab2ca7da1..2da986a1494 100644 --- a/library/std/src/sys/pal/windows/process.rs +++ b/library/std/src/sys/pal/windows/process.rs @@ -31,6 +31,8 @@ use crate::sys_common::IntoInner; use core::ffi::c_void; +use super::api::{self, WinError}; + //////////////////////////////////////////////////////////////////////////////// // Command //////////////////////////////////////////////////////////////////////////////// @@ -645,12 +647,12 @@ impl Process { pub fn kill(&mut self) -> io::Result<()> { let result = unsafe { c::TerminateProcess(self.handle.as_raw_handle(), 1) }; if result == c::FALSE { - let error = unsafe { c::GetLastError() }; + let error = api::get_last_error(); // TerminateProcess returns ERROR_ACCESS_DENIED if the process has already been // terminated (by us, or for any other reason). So check if the process was actually // terminated, and if so, do not return an error. - if error != c::ERROR_ACCESS_DENIED || self.try_wait().is_err() { - return Err(crate::io::Error::from_raw_os_error(error as i32)); + if error != WinError::ACCESS_DENIED || self.try_wait().is_err() { + return Err(crate::io::Error::from_raw_os_error(error.code as i32)); } } Ok(()) diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/pal/windows/stdio.rs index 96c23f82aec..690b60d1dec 100644 --- a/library/std/src/sys/pal/windows/stdio.rs +++ b/library/std/src/sys/pal/windows/stdio.rs @@ -1,6 +1,6 @@ #![unstable(issue = "none", feature = "windows_stdio")] -use super::api; +use super::api::{self, WinError}; use crate::cmp; use crate::io; use crate::mem::MaybeUninit; @@ -370,7 +370,7 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit<u16>]) -> io::Result<usiz // ReadConsoleW returns success with ERROR_OPERATION_ABORTED for Ctrl-C or Ctrl-Break. // Explicitly check for that case here and try again. - if amount == 0 && api::get_last_error().code == c::ERROR_OPERATION_ABORTED { + if amount == 0 && api::get_last_error() == WinError::OPERATION_ABORTED { continue; } break; diff --git a/library/std/src/sys/thread_local/fast_local/eager.rs b/library/std/src/sys/thread_local/fast_local/eager.rs index c2bc580530b..b97bd9cc88c 100644 --- a/library/std/src/sys/thread_local/fast_local/eager.rs +++ b/library/std/src/sys/thread_local/fast_local/eager.rs @@ -21,43 +21,35 @@ impl<T> Storage<T> { Storage { state: Cell::new(State::Initial), val: UnsafeCell::new(val) } } - /// Get a reference to the TLS value. If the TLS variable has been destroyed, - /// `None` is returned. + /// Get a pointer to the TLS value. If the TLS variable has been destroyed, + /// a null pointer is returned. /// - /// # Safety - /// * The `self` reference must remain valid until the TLS destructor has been - /// run. - /// * The returned reference may only be used until thread destruction occurs - /// and may not be used after reentrant initialization has occurred. + /// The resulting pointer may not be used after thread destruction has + /// occurred. /// - // FIXME(#110897): return NonNull instead of lying about the lifetime. + /// # Safety + /// The `self` reference must remain valid until the TLS destructor is run. #[inline] - pub unsafe fn get(&self) -> Option<&'static T> { + pub unsafe fn get(&self) -> *const T { match self.state.get() { - // SAFETY: as the state is not `Destroyed`, the value cannot have - // been destroyed yet. The reference fulfills the terms outlined - // above. - State::Alive => unsafe { Some(&*self.val.get()) }, - State::Destroyed => None, + State::Alive => self.val.get(), + State::Destroyed => ptr::null(), State::Initial => unsafe { self.initialize() }, } } #[cold] - unsafe fn initialize(&self) -> Option<&'static T> { + unsafe fn initialize(&self) -> *const T { // Register the destructor // SAFETY: - // * the destructor will be called at thread destruction. - // * the caller guarantees that `self` will be valid until that time. + // The caller guarantees that `self` will be valid until thread destruction. unsafe { register_dtor(ptr::from_ref(self).cast_mut().cast(), destroy::<T>); } + self.state.set(State::Alive); - // SAFETY: as the state is not `Destroyed`, the value cannot have - // been destroyed yet. The reference fulfills the terms outlined - // above. - unsafe { Some(&*self.val.get()) } + self.val.get() } } diff --git a/library/std/src/sys/thread_local/fast_local/lazy.rs b/library/std/src/sys/thread_local/fast_local/lazy.rs index c2e9a171454..c1ada35d484 100644 --- a/library/std/src/sys/thread_local/fast_local/lazy.rs +++ b/library/std/src/sys/thread_local/fast_local/lazy.rs @@ -39,49 +39,31 @@ where Storage { state: UnsafeCell::new(State::Initial) } } - /// Get a reference to the TLS value, potentially initializing it with the - /// provided parameters. If the TLS variable has been destroyed, `None` is - /// returned. + /// Get a pointer to the TLS value, potentially initializing it with the + /// provided parameters. If the TLS variable has been destroyed, a null + /// pointer is returned. /// - /// # Safety - /// * The `self` reference must remain valid until the TLS destructor is run, - /// at which point the returned reference is invalidated. - /// * The returned reference may only be used until thread destruction occurs - /// and may not be used after reentrant initialization has occurred. + /// The resulting pointer may not be used after reentrant inialialization + /// or thread destruction has occurred. /// - // FIXME(#110897): return NonNull instead of lying about the lifetime. + /// # Safety + /// The `self` reference must remain valid until the TLS destructor is run. #[inline] - pub unsafe fn get_or_init( - &self, - i: Option<&mut Option<T>>, - f: impl FnOnce() -> T, - ) -> Option<&'static T> { - // SAFETY: - // No mutable reference to the inner value exists outside the calls to - // `replace`. The lifetime of the returned reference fulfills the terms - // outlined above. + pub unsafe fn get_or_init(&self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T { let state = unsafe { &*self.state.get() }; match state { - State::Alive(v) => Some(v), - State::Destroyed(_) => None, + State::Alive(v) => v, + State::Destroyed(_) => ptr::null(), State::Initial => unsafe { self.initialize(i, f) }, } } #[cold] - unsafe fn initialize( - &self, - i: Option<&mut Option<T>>, - f: impl FnOnce() -> T, - ) -> Option<&'static T> { + unsafe fn initialize(&self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T { // Perform initialization let v = i.and_then(Option::take).unwrap_or_else(f); - // SAFETY: - // If references to the inner value exist, they were created in `f` - // and are invalidated here. The caller promises to never use them - // after this. let old = unsafe { self.state.get().replace(State::Alive(v)) }; match old { // If the variable is not being recursively initialized, register @@ -92,12 +74,10 @@ where val => drop(val), } - // SAFETY: - // Initialization was completed and the state was set to `Alive`, so the - // reference fulfills the terms outlined above. + // SAFETY: the state was just set to `Alive` unsafe { let State::Alive(v) = &*self.state.get() else { unreachable_unchecked() }; - Some(v) + v } } } diff --git a/library/std/src/sys/thread_local/fast_local/mod.rs b/library/std/src/sys/thread_local/fast_local/mod.rs index 152137d9270..575d60de4ee 100644 --- a/library/std/src/sys/thread_local/fast_local/mod.rs +++ b/library/std/src/sys/thread_local/fast_local/mod.rs @@ -52,32 +52,26 @@ pub macro thread_local_inner { (@key $t:ty, const $init:expr) => {{ const __INIT: $t = $init; - #[inline] - #[deny(unsafe_op_in_unsafe_fn)] - unsafe fn __getit( - _init: $crate::option::Option<&mut $crate::option::Option<$t>>, - ) -> $crate::option::Option<&'static $t> { - use $crate::thread::local_impl::EagerStorage; + unsafe { use $crate::mem::needs_drop; - use $crate::ptr::addr_of; + use $crate::thread::LocalKey; + use $crate::thread::local_impl::EagerStorage; - if needs_drop::<$t>() { - #[thread_local] - static VAL: EagerStorage<$t> = EagerStorage::new(__INIT); - unsafe { - VAL.get() + LocalKey::new(const { + if needs_drop::<$t>() { + |_| { + #[thread_local] + static VAL: EagerStorage<$t> = EagerStorage::new(__INIT); + VAL.get() + } + } else { + |_| { + #[thread_local] + static VAL: $t = __INIT; + &VAL + } } - } else { - #[thread_local] - static VAL: $t = __INIT; - unsafe { - $crate::option::Option::Some(&*addr_of!(VAL)) - } - } - } - - unsafe { - $crate::thread::LocalKey::new(__getit) + }) } }}, @@ -88,31 +82,26 @@ pub macro thread_local_inner { $init } - #[inline] - #[deny(unsafe_op_in_unsafe_fn)] - unsafe fn __getit( - init: $crate::option::Option<&mut $crate::option::Option<$t>>, - ) -> $crate::option::Option<&'static $t> { - use $crate::thread::local_impl::LazyStorage; + unsafe { use $crate::mem::needs_drop; + use $crate::thread::LocalKey; + use $crate::thread::local_impl::LazyStorage; - if needs_drop::<$t>() { - #[thread_local] - static VAL: LazyStorage<$t, ()> = LazyStorage::new(); - unsafe { - VAL.get_or_init(init, __init) + LocalKey::new(const { + if needs_drop::<$t>() { + |init| { + #[thread_local] + static VAL: LazyStorage<$t, ()> = LazyStorage::new(); + VAL.get_or_init(init, __init) + } + } else { + |init| { + #[thread_local] + static VAL: LazyStorage<$t, !> = LazyStorage::new(); + VAL.get_or_init(init, __init) + } } - } else { - #[thread_local] - static VAL: LazyStorage<$t, !> = LazyStorage::new(); - unsafe { - VAL.get_or_init(init, __init) - } - } - } - - unsafe { - $crate::thread::LocalKey::new(__getit) + }) } }}, ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => { diff --git a/library/std/src/sys/thread_local/os_local.rs b/library/std/src/sys/thread_local/os_local.rs index d6ddbb78a9c..ee5adef66ea 100644 --- a/library/std/src/sys/thread_local/os_local.rs +++ b/library/std/src/sys/thread_local/os_local.rs @@ -16,30 +16,22 @@ pub macro thread_local_inner { }, // used to generate the `LocalKey` value for `thread_local!` - (@key $t:ty, $init:expr) => { - { - #[inline] - fn __init() -> $t { $init } + (@key $t:ty, $init:expr) => {{ + #[inline] + fn __init() -> $t { $init } - // `#[inline] does not work on windows-gnu due to linking errors around dllimports. - // See https://github.com/rust-lang/rust/issues/109797. - #[cfg_attr(not(windows), inline)] - unsafe fn __getit( - init: $crate::option::Option<&mut $crate::option::Option<$t>>, - ) -> $crate::option::Option<&'static $t> { - use $crate::thread::local_impl::Key; - - static __KEY: Key<$t> = Key::new(); - unsafe { - __KEY.get(init, __init) - } - } + unsafe { + use $crate::thread::LocalKey; + use $crate::thread::local_impl::Key; - unsafe { - $crate::thread::LocalKey::new(__getit) - } + // Inlining does not work on windows-gnu due to linking errors around + // dllimports. See https://github.com/rust-lang/rust/issues/109797. + LocalKey::new(#[cfg_attr(windows, inline(never))] |init| { + static VAL: Key<$t> = Key::new(); + VAL.get(init, __init) + }) } - }, + }}, ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => { $(#[$attr])* $vis const $name: $crate::thread::LocalKey<$t> = $crate::thread::local_impl::thread_local_inner!(@key $t, $($init)*); @@ -67,38 +59,33 @@ impl<T: 'static> Key<T> { Key { os: OsKey::new(Some(destroy_value::<T>)), marker: PhantomData } } - /// Get the value associated with this key, initializating it if necessary. + /// Get a pointer to the TLS value, potentially initializing it with the + /// provided parameters. If the TLS variable has been destroyed, a null + /// pointer is returned. /// - /// # Safety - /// * the returned reference must not be used after recursive initialization - /// or thread destruction occurs. - pub unsafe fn get( - &'static self, - i: Option<&mut Option<T>>, - f: impl FnOnce() -> T, - ) -> Option<&'static T> { + /// The resulting pointer may not be used after reentrant inialialization + /// or thread destruction has occurred. + pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T { // SAFETY: (FIXME: get should actually be safe) let ptr = unsafe { self.os.get() as *mut Value<T> }; if ptr.addr() > 1 { // SAFETY: the check ensured the pointer is safe (its destructor // is not running) + it is coming from a trusted source (self). - unsafe { Some(&(*ptr).value) } + unsafe { &(*ptr).value } } else { - // SAFETY: At this point we are sure we have no value and so - // initializing (or trying to) is safe. - unsafe { self.try_initialize(ptr, i, f) } + self.try_initialize(ptr, i, f) } } - unsafe fn try_initialize( + fn try_initialize( &'static self, ptr: *mut Value<T>, i: Option<&mut Option<T>>, f: impl FnOnce() -> T, - ) -> Option<&'static T> { + ) -> *const T { if ptr.addr() == 1 { // destructor is running - return None; + return ptr::null(); } let value = i.and_then(Option::take).unwrap_or_else(f); @@ -119,7 +106,7 @@ impl<T: 'static> Key<T> { } // SAFETY: We just created this value above. - unsafe { Some(&(*ptr).value) } + unsafe { &(*ptr).value } } } diff --git a/library/std/src/sys/thread_local/static_local.rs b/library/std/src/sys/thread_local/static_local.rs index 6beda2e7188..0f08cab1ae4 100644 --- a/library/std/src/sys/thread_local/static_local.rs +++ b/library/std/src/sys/thread_local/static_local.rs @@ -13,19 +13,14 @@ pub macro thread_local_inner { (@key $t:ty, const $init:expr) => {{ const __INIT: $t = $init; - #[inline] - #[deny(unsafe_op_in_unsafe_fn)] - unsafe fn __getit( - _init: $crate::option::Option<&mut $crate::option::Option<$t>>, - ) -> $crate::option::Option<&'static $t> { + unsafe { + use $crate::thread::LocalKey; use $crate::thread::local_impl::EagerStorage; - static VAL: EagerStorage<$t> = EagerStorage { value: __INIT }; - $crate::option::Option::Some(&VAL.value) - } - - unsafe { - $crate::thread::LocalKey::new(__getit) + LocalKey::new(|_| { + static VAL: EagerStorage<$t> = EagerStorage { value: __INIT }; + &VAL.value + }) } }}, @@ -34,19 +29,14 @@ pub macro thread_local_inner { #[inline] fn __init() -> $t { $init } - #[inline] - #[deny(unsafe_op_in_unsafe_fn)] - unsafe fn __getit( - init: $crate::option::Option<&mut $crate::option::Option<$t>>, - ) -> $crate::option::Option<&'static $t> { + unsafe { + use $crate::thread::LocalKey; use $crate::thread::local_impl::LazyStorage; - static VAL: LazyStorage<$t> = LazyStorage::new(); - unsafe { $crate::option::Option::Some(VAL.get(init, __init)) } - } - - unsafe { - $crate::thread::LocalKey::new(__getit) + LocalKey::new(|init| { + static VAL: LazyStorage<$t> = LazyStorage::new(); + VAL.get(init, __init) + }) } }}, ($(#[$attr:meta])* $vis:vis $name:ident, $t:ty, $($init:tt)*) => { @@ -73,16 +63,13 @@ impl<T> LazyStorage<T> { LazyStorage { value: UnsafeCell::new(None) } } - /// Gets a reference to the contained value, initializing it if necessary. + /// Get a pointer to the TLS value, potentially initializing it with the + /// provided parameters. /// - /// # Safety - /// The returned reference may not be used after reentrant initialization has occurred. + /// The resulting pointer may not be used after reentrant inialialization + /// has occurred. #[inline] - pub unsafe fn get( - &'static self, - i: Option<&mut Option<T>>, - f: impl FnOnce() -> T, - ) -> &'static T { + pub fn get(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T { let value = unsafe { &*self.value.get() }; match value { Some(v) => v, @@ -91,11 +78,7 @@ impl<T> LazyStorage<T> { } #[cold] - unsafe fn initialize( - &'static self, - i: Option<&mut Option<T>>, - f: impl FnOnce() -> T, - ) -> &'static T { + fn initialize(&'static self, i: Option<&mut Option<T>>, f: impl FnOnce() -> T) -> *const T { let value = i.and_then(Option::take).unwrap_or_else(f); // Destroy the old value, after updating the TLS variable as the // destructor might reference it. diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 38e15f9f549..bb1e505285b 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -325,6 +325,11 @@ impl Wtf8Buf { self.bytes.shrink_to(min_capacity) } + #[inline] + pub fn leak<'a>(self) -> &'a mut Wtf8 { + unsafe { Wtf8::from_mut_bytes_unchecked(self.bytes.leak()) } + } + /// Returns the number of bytes that this string buffer can hold without reallocating. #[inline] pub fn capacity(&self) -> usize { diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index c1b4440e560..aed185637fd 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -123,7 +123,7 @@ pub struct LocalKey<T: 'static> { // trivially devirtualizable by LLVM because the value of `inner` never // changes and the constant should be readonly within a crate. This mainly // only runs into problems when TLS statics are exported across crates. - inner: unsafe fn(Option<&mut Option<T>>) -> Option<&'static T>, + inner: fn(Option<&mut Option<T>>) -> *const T, } #[stable(feature = "std_debug", since = "1.16.0")] @@ -238,9 +238,7 @@ impl<T: 'static> LocalKey<T> { issue = "none" )] #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] - pub const unsafe fn new( - inner: unsafe fn(Option<&mut Option<T>>) -> Option<&'static T>, - ) -> LocalKey<T> { + pub const unsafe fn new(inner: fn(Option<&mut Option<T>>) -> *const T) -> LocalKey<T> { LocalKey { inner } } @@ -281,8 +279,7 @@ impl<T: 'static> LocalKey<T> { where F: FnOnce(&T) -> R, { - // SAFETY: `inner` is safe to call within the lifetime of the thread - let thread_local = unsafe { (self.inner)(None).ok_or(AccessError)? }; + let thread_local = unsafe { (self.inner)(None).as_ref().ok_or(AccessError)? }; Ok(f(thread_local)) } @@ -304,9 +301,8 @@ impl<T: 'static> LocalKey<T> { { let mut init = Some(init); - // SAFETY: `inner` is safe to call within the lifetime of the thread let reference = unsafe { - (self.inner)(Some(&mut init)).expect( + (self.inner)(Some(&mut init)).as_ref().expect( "cannot access a Thread Local Storage value \ during or after destruction", ) diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 22215873933..83e27dfb746 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -561,7 +561,8 @@ impl Builder { let main = Box::new(main); // SAFETY: dynamic size and alignment of the Box remain the same. See below for why the // lifetime change is justified. - let main = unsafe { Box::from_raw(Box::into_raw(main) as *mut (dyn FnOnce() + 'static)) }; + let main = + unsafe { Box::from_raw(Box::into_raw(main) as *mut (dyn FnOnce() + Send + 'static)) }; Ok(JoinInner { // SAFETY: @@ -1544,7 +1545,7 @@ struct Packet<'scope, T> { // The type `T` should already always be Send (otherwise the thread could not // have been created) and the Packet is Sync because all access to the // `UnsafeCell` synchronized (by the `join()` boundary), and `ScopeData` is Sync. -unsafe impl<'scope, T: Sync> Sync for Packet<'scope, T> {} +unsafe impl<'scope, T: Send> Sync for Packet<'scope, T> {} impl<'scope, T> Drop for Packet<'scope, T> { fn drop(&mut self) { diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml index 0e2409f63ab..75cc7c00e38 100644 --- a/library/test/Cargo.toml +++ b/library/test/Cargo.toml @@ -7,8 +7,6 @@ edition = "2021" getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] } std = { path = "../std" } core = { path = "../core" } -panic_unwind = { path = "../panic_unwind" } -panic_abort = { path = "../panic_abort" } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] libc = { version = "0.2.150", default-features = false } diff --git a/rustfmt.toml b/rustfmt.toml index 2b502cf9bc6..b15ffdca38a 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -10,27 +10,18 @@ ignore = [ "/build-*/", "/vendor/", - # Some tests are not formatted, for multiple reasons: - # - some contain syntax errors that cause rustfmt to give an error - # - some UI tests are broken by different formatting - # - some require special comments in a particular position (e.g. `EMIT_MIR` comments) + # Some tests are not formatted, for various reasons. "/tests/codegen/simd-intrinsic/", # Many types like `u8x64` are better hand-formatted. - "/tests/crashes/", # Many tests contain syntax errors. - "/tests/debuginfo/", # Tests are somewhat sensitive to source code layout. - "/tests/incremental/", # Tests are somewhat sensitive to source code layout. - "/tests/mir-opt/", - "/tests/pretty/", - "/tests/run-make/translation/test.rs", # Contains syntax errors. - "/tests/run-make-fulldeps/", - "/tests/run-pass-valgrind/", - "/tests/rustdoc/", - "/tests/rustdoc-gui/", - "/tests/rustdoc-js/", - "/tests/rustdoc-json/", - "/tests/rustdoc-js-std/", - "/tests/rustdoc-ui/", - "/tests/ui/", - "/tests/ui-fulldeps/", + "/tests/crashes/", # Many of these tests contain syntax errors. + "/tests/debuginfo/", # These tests are somewhat sensitive to source code layout. + "/tests/incremental/", # These tests are somewhat sensitive to source code layout. + "/tests/pretty/", # These tests are very sensitive to source code layout. + "/tests/run-make/translation/test.rs", # This test contains syntax errors. + "/tests/rustdoc/", # Some have syntax errors, some are whitespace-sensitive. + "/tests/rustdoc-gui/", # Some tests are sensitive to source code layout. + "/tests/rustdoc-ui/", # Some have syntax errors, some are whitespace-sensitive. + "/tests/ui/", # Some have syntax errors, some are whitespace-sensitive. + "/tests/ui-fulldeps/", # Some are whitespace-sensitive (e.g. `// ~ERROR` comments). # Do not format submodules. # FIXME: sync submodule list with tidy/bootstrap/etc diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index ca0d1fa5bd0..32dd3efa7a6 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -7,6 +7,7 @@ default-run = "bootstrap" [features] build-metrics = ["sysinfo"] +bootstrap-self-test = [] # enabled in the bootstrap unit tests [lib] path = "src/lib.rs" diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index e60e8f0aa1f..9861121aac0 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -599,6 +599,12 @@ class RustBuild(object): print('Choosing a pool size of', pool_size, 'for the unpacking of the tarballs') p = Pool(pool_size) try: + # FIXME: A cheap workaround for https://github.com/rust-lang/rust/issues/125578, + # remove this once the issue is closed. + bootstrap_out = self.bootstrap_out() + if os.path.exists(bootstrap_out): + shutil.rmtree(bootstrap_out) + p.map(unpack_component, tarballs_download_info) finally: p.close() @@ -864,6 +870,16 @@ class RustBuild(object): return line[start + 1:end] return None + def bootstrap_out(self): + """Return the path of the bootstrap build artifacts + + >>> rb = RustBuild() + >>> rb.build_dir = "build" + >>> rb.bootstrap_binary() == os.path.join("build", "bootstrap") + True + """ + return os.path.join(self.build_dir, "bootstrap") + def bootstrap_binary(self): """Return the path of the bootstrap binary @@ -873,7 +889,7 @@ class RustBuild(object): ... "debug", "bootstrap") True """ - return os.path.join(self.build_dir, "bootstrap", "debug", "bootstrap") + return os.path.join(self.bootstrap_out(), "debug", "bootstrap") def build_bootstrap(self): """Build bootstrap""" diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index fc433bc5843..cab37e0da47 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -59,17 +59,18 @@ check-aux: library/alloc \ --no-doc # Some doctests have intentional memory leaks. + # Some use file system operations to demonstrate dealing with `Result`. $(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" \ $(BOOTSTRAP) miri --stage 2 \ library/core \ library/alloc \ --doc - # In `std` we cannot test everything. - $(Q)MIRIFLAGS="-Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \ + # In `std` we cannot test everything, so we skip some modules. + $(Q)MIRIFLAGS="-Zmiri-disable-isolation" \ $(BOOTSTRAP) miri --stage 2 library/std \ --no-doc -- \ --skip fs:: --skip net:: --skip process:: --skip sys::pal:: - $(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \ + $(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" \ $(BOOTSTRAP) miri --stage 2 library/std \ --doc -- \ --skip fs:: --skip net:: --skip process:: --skip sys::pal:: diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 91039d0c8dc..60b1ff3e441 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1041,6 +1041,21 @@ impl Step for PlainSourceTarball { .env("RUSTC_BOOTSTRAP", "1") .current_dir(plain_dst_src); + // Vendor packages that are required by opt-dist to collect PGO profiles. + let pkgs_for_pgo_training = build_helper::LLVM_PGO_CRATES + .iter() + .chain(build_helper::RUSTC_PGO_CRATES) + .map(|pkg| { + let mut manifest_path = + builder.src.join("./src/tools/rustc-perf/collector/compile-benchmarks"); + manifest_path.push(pkg); + manifest_path.push("Cargo.toml"); + manifest_path + }); + for manifest_path in pkgs_for_pgo_training { + cmd.arg("--sync").arg(manifest_path); + } + let config = if !builder.config.dry_run() { t!(String::from_utf8(t!(cmd.output()).stdout)) } else { diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 30b3edfd3ae..b37b2b5bcef 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -29,7 +29,7 @@ macro_rules! submodule_helper { } macro_rules! book { - ($($name:ident, $path:expr, $book_name:expr $(, submodule $(= $submodule:literal)? )? ;)+) => { + ($($name:ident, $path:expr, $book_name:expr, $lang:expr $(, submodule $(= $submodule:literal)? )? ;)+) => { $( #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct $name { @@ -61,6 +61,7 @@ macro_rules! book { name: $book_name.to_owned(), src: builder.src.join($path), parent: Some(self), + languages: $lang.into(), }) } } @@ -74,15 +75,15 @@ macro_rules! book { // FIXME: Make checking for a submodule automatic somehow (maybe by having a list of all submodules // and checking against it?). book!( - CargoBook, "src/tools/cargo/src/doc", "cargo", submodule = "src/tools/cargo"; - ClippyBook, "src/tools/clippy/book", "clippy"; - EditionGuide, "src/doc/edition-guide", "edition-guide", submodule; - EmbeddedBook, "src/doc/embedded-book", "embedded-book", submodule; - Nomicon, "src/doc/nomicon", "nomicon", submodule; - Reference, "src/doc/reference", "reference", submodule; - RustByExample, "src/doc/rust-by-example", "rust-by-example", submodule; - RustdocBook, "src/doc/rustdoc", "rustdoc"; - StyleGuide, "src/doc/style-guide", "style-guide"; + CargoBook, "src/tools/cargo/src/doc", "cargo", &[], submodule = "src/tools/cargo"; + ClippyBook, "src/tools/clippy/book", "clippy", &[]; + EditionGuide, "src/doc/edition-guide", "edition-guide", &[], submodule; + EmbeddedBook, "src/doc/embedded-book", "embedded-book", &[], submodule; + Nomicon, "src/doc/nomicon", "nomicon", &[], submodule; + Reference, "src/doc/reference", "reference", &[], submodule; + RustByExample, "src/doc/rust-by-example", "rust-by-example", &["ja"], submodule; + RustdocBook, "src/doc/rustdoc", "rustdoc", &[]; + StyleGuide, "src/doc/style-guide", "style-guide", &[]; ); #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -110,6 +111,7 @@ impl Step for UnstableBook { name: "unstable-book".to_owned(), src: builder.md_doc_out(self.target).join("unstable-book"), parent: Some(self), + languages: vec![], }) } } @@ -120,6 +122,7 @@ struct RustbookSrc<P: Step> { name: String, src: PathBuf, parent: Option<P>, + languages: Vec<&'static str>, } impl<P: Step> Step for RustbookSrc<P> { @@ -151,7 +154,19 @@ impl<P: Step> Step for RustbookSrc<P> { builder.info(&format!("Rustbook ({target}) - {name}")); let _ = fs::remove_dir_all(&out); - builder.run(rustbook_cmd.arg("build").arg(src).arg("-d").arg(out)); + builder.run(rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out)); + + for lang in &self.languages { + let out = out.join(lang); + + builder.info(&format!("Rustbook ({target}) - {name} - {lang}")); + let _ = fs::remove_dir_all(&out); + + let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook); + builder.run( + rustbook_cmd.arg("build").arg(&src).arg("-d").arg(&out).arg("-l").arg(lang), + ); + } } if self.parent.is_some() { @@ -214,6 +229,7 @@ impl Step for TheBook { name: "book".to_owned(), src: absolute_path.clone(), parent: Some(self), + languages: vec![], }); // building older edition redirects @@ -225,6 +241,7 @@ impl Step for TheBook { // There should only be one book that is marked as the parent for each target, so // treat the other editions as not having a parent. parent: Option::<Self>::None, + languages: vec![], }); } @@ -1208,6 +1225,7 @@ impl Step for RustcBook { name: "rustc".to_owned(), src: out_base, parent: Some(self), + languages: vec![], }); } } diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 601e4e55e09..0caa39d78ac 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -118,7 +118,9 @@ fn print_paths(verb: &str, adjective: Option<&str>, paths: &[String]) { pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { if !paths.is_empty() { - eprintln!("fmt error: path arguments are not accepted"); + eprintln!( + "fmt error: path arguments are no longer accepted; use `--all` to format everything" + ); crate::exit!(1); }; if build.config.dry_run() { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 29b3d1669b4..29cd90222b2 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1101,6 +1101,8 @@ impl Step for Tidy { /// Once tidy passes, this step also runs `fmt --check` if tests are being run /// for the `dev` or `nightly` channels. fn run(self, builder: &Builder<'_>) { + builder.build.update_submodule(Path::new("src/tools/rustc-perf")); + let mut cmd = builder.tool_cmd(Tool::Tidy); cmd.arg(&builder.src); cmd.arg(&builder.initial_cargo); @@ -1487,12 +1489,6 @@ impl Step for RunMake { } } -host_test!(RunMakeFullDeps { - path: "tests/run-make-fulldeps", - mode: "run-make", - suite: "run-make-fulldeps" -}); - default_test!(Assembly { path: "tests/assembly", mode: "assembly", suite: "assembly" }); /// Coverage tests are a bit more complicated than other test suites, because @@ -1973,9 +1969,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cmd); } - if !builder.config.dry_run() - && (matches!(suite, "run-make" | "run-make-fulldeps") || mode == "coverage-run") - { + if !builder.config.dry_run() && matches!(mode, "run-make" | "coverage-run") { // The llvm/bin directory contains many useful cross-platform // tools. Pass the path to run-make tests so they can use them. // (The coverage-run tests also need these tools to process @@ -1987,7 +1981,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--llvm-bin-dir").arg(llvm_bin_path); } - if !builder.config.dry_run() && matches!(suite, "run-make" | "run-make-fulldeps") { + if !builder.config.dry_run() && mode == "run-make" { // If LLD is available, add it to the PATH if builder.config.lld_enabled { let lld_install_root = @@ -2007,7 +2001,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // Only pass correct values for these flags for the `run-make` suite as it // requires that a C++ compiler was configured which isn't always the case. - if !builder.config.dry_run() && matches!(suite, "run-make" | "run-make-fulldeps") { + if !builder.config.dry_run() && mode == "run-make" { cmd.arg("--cc") .arg(builder.cc(target)) .arg("--cxx") @@ -3053,6 +3047,7 @@ impl Step for Bootstrap { let mut cmd = Command::new(&builder.initial_cargo); cmd.arg("test") + .args(["--features", "bootstrap-self-test"]) .current_dir(builder.src.join("src/bootstrap")) .env("RUSTFLAGS", "-Cdebuginfo=2") .env("CARGO_TARGET_DIR", builder.out.join("bootstrap")) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 2db3f8f7936..9df4698f21f 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -9,7 +9,7 @@ use crate::core::builder; use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; use crate::core::config::TargetSelection; use crate::utils::channel::GitInfo; -use crate::utils::exec::BootstrapCommand; +use crate::utils::helpers::output; use crate::utils::helpers::{add_dylib_path, exe, t}; use crate::Compiler; use crate::Mode; @@ -109,9 +109,8 @@ impl Step for ToolBuild { &self.target, ); - let mut cargo = Command::from(cargo); // we check this below - let build_success = builder.run_cmd(BootstrapCommand::from(&mut cargo).allow_failure()); + let build_success = compile::stream_cargo(builder, cargo, vec![], &mut |_| {}); builder.save_toolstate( tool, @@ -804,6 +803,59 @@ impl Step for LlvmBitcodeLinker { } } +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct LibcxxVersionTool { + pub target: TargetSelection, +} + +#[allow(dead_code)] +#[derive(Debug, Clone)] +pub enum LibcxxVersion { + Gnu(usize), + Llvm(usize), +} + +impl Step for LibcxxVersionTool { + type Output = LibcxxVersion; + const DEFAULT: bool = false; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.never() + } + + fn run(self, builder: &Builder<'_>) -> LibcxxVersion { + let out_dir = builder.out.join(self.target.to_string()).join("libcxx-version"); + let _ = fs::remove_dir_all(&out_dir); + t!(fs::create_dir_all(&out_dir)); + + let compiler = builder.cxx(self.target).unwrap(); + let mut cmd = Command::new(compiler); + + let executable = out_dir.join(exe("libcxx-version", self.target)); + cmd.arg("-o").arg(&executable).arg(builder.src.join("src/tools/libcxx-version/main.cpp")); + + builder.run_cmd(&mut cmd); + + if !executable.exists() { + panic!("Something went wrong. {} is not present", executable.display()); + } + + let version_output = output(&mut Command::new(executable)); + + let version_str = version_output.split_once("version:").unwrap().1; + let version = version_str.trim().parse::<usize>().unwrap(); + + if version_output.starts_with("libstdc++") { + LibcxxVersion::Gnu(version) + } else if version_output.starts_with("libc++") { + LibcxxVersion::Llvm(version) + } else { + panic!("Coudln't recognize the standard library version."); + } + } +} + macro_rules! tool_extended { (($sel:ident, $builder:ident), $($name:ident, diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index b3d8465cda9..12d2bb18ab7 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -332,7 +332,6 @@ const PATH_REMAP: &[(&str, &[&str])] = &[ "tests/mir-opt", "tests/pretty", "tests/run-make", - "tests/run-make-fulldeps", "tests/run-pass-valgrind", "tests/rustdoc", "tests/rustdoc-gui", @@ -828,7 +827,6 @@ impl<'a> Builder<'a> { test::RustAnalyzer, test::ErrorIndex, test::Distcheck, - test::RunMakeFullDeps, test::Nomicon, test::Reference, test::RustdocBook, @@ -1038,14 +1036,26 @@ impl<'a> Builder<'a> { } pub fn doc_rust_lang_org_channel(&self) -> String { - let channel = match &*self.config.channel { - "stable" => &self.version, - "beta" => "beta", - "nightly" | "dev" => "nightly", - // custom build of rustdoc maybe? link to the latest stable docs just in case - _ => "stable", + // When using precompiled compiler from CI, we need to use CI rustc's channel and + // ignore `rust.channel` from the configuration. Otherwise most of the rustdoc tests + // will fail due to incompatible `DOC_RUST_LANG_ORG_CHANNEL`. + let channel = if let Some(commit) = self.config.download_rustc_commit() { + self.config + .read_file_by_commit(&PathBuf::from("src/ci/channel"), commit) + .trim() + .to_owned() + } else { + match &*self.config.channel { + "stable" => &self.version, + "beta" => "beta", + "nightly" | "dev" => "nightly", + // custom build of rustdoc maybe? link to the latest stable docs just in case + _ => "stable", + } + .to_owned() }; - "https://doc.rust-lang.org/".to_owned() + channel + + format!("https://doc.rust-lang.org/{channel}") } fn run_step_descriptions(&self, v: &[StepDescription], paths: &[PathBuf]) { diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 70d32f2f6d9..36b44d0169c 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -22,8 +22,6 @@ use crate::utils::cache::{Interned, INTERNER}; use crate::utils::channel::{self, GitInfo}; use crate::utils::helpers::{exe, output, t}; use build_helper::exit; -use build_helper::util::fail; -use semver::Version; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; @@ -1610,19 +1608,8 @@ impl Config { set(&mut config.channel, channel); config.download_rustc_commit = config.download_ci_rustc_commit(download_rustc); - // This list is incomplete, please help by expanding it! - if config.download_rustc_commit.is_some() { - // We need the channel used by the downloaded compiler to match the one we set for rustdoc; - // otherwise rustdoc-ui tests break. - if config.channel != ci_channel - && !(config.channel == "dev" && ci_channel == "nightly") - { - panic!( - "setting rust.channel={} is incompatible with download-rustc", - config.channel - ); - } - } + + // FIXME: handle download-rustc incompatible options. debug = debug_toml; debug_assertions = debug_assertions_toml; @@ -2136,17 +2123,29 @@ impl Config { args } + /// Returns the content of the given file at a specific commit. + pub(crate) fn read_file_by_commit(&self, file: &Path, commit: &str) -> String { + assert!( + self.rust_info.is_managed_git_subrepository(), + "`Config::read_file_by_commit` is not supported in non-git sources." + ); + + let mut git = self.git(); + git.arg("show").arg(format!("{commit}:{}", file.to_str().unwrap())); + output(&mut git) + } + /// Bootstrap embeds a version number into the name of shared libraries it uploads in CI. /// Return the version it would have used for the given commit. pub(crate) fn artifact_version_part(&self, commit: &str) -> String { let (channel, version) = if self.rust_info.is_managed_git_subrepository() { - let mut channel = self.git(); - channel.arg("show").arg(format!("{commit}:src/ci/channel")); - let channel = output(&mut channel); - let mut version = self.git(); - version.arg("show").arg(format!("{commit}:src/version")); - let version = output(&mut version); - (channel.trim().to_owned(), version.trim().to_owned()) + let channel = self + .read_file_by_commit(&PathBuf::from("src/ci/channel"), commit) + .trim() + .to_owned(); + let version = + self.read_file_by_commit(&PathBuf::from("src/version"), commit).trim().to_owned(); + (channel, version) } else { let channel = fs::read_to_string(self.src.join("src/ci/channel")); let version = fs::read_to_string(self.src.join("src/version")); @@ -2382,8 +2381,14 @@ impl Config { } } - // check rustc/cargo version is same or lower with 1 apart from the building one + #[cfg(feature = "bootstrap-self-test")] + pub fn check_stage0_version(&self, _program_path: &Path, _component_name: &'static str) {} + + /// check rustc/cargo version is same or lower with 1 apart from the building one + #[cfg(not(feature = "bootstrap-self-test"))] pub fn check_stage0_version(&self, program_path: &Path, component_name: &'static str) { + use build_helper::util::fail; + if self.dry_run() { return; } @@ -2400,11 +2405,12 @@ impl Config { } let stage0_version = - Version::parse(stage0_output.next().unwrap().split('-').next().unwrap().trim()) - .unwrap(); - let source_version = - Version::parse(fs::read_to_string(self.src.join("src/version")).unwrap().trim()) + semver::Version::parse(stage0_output.next().unwrap().split('-').next().unwrap().trim()) .unwrap(); + let source_version = semver::Version::parse( + fs::read_to_string(self.src.join("src/version")).unwrap().trim(), + ) + .unwrap(); if !(source_version == stage0_version || (source_version.major == stage0_version.major && (source_version.minor == stage0_version.minor diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index c4073910623..bfb2c02860d 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -14,16 +14,9 @@ use std::{ }; fn parse(config: &str) -> Config { - Config::parse_inner( - &[ - "check".to_string(), - "--set=build.rustc=/does/not/exist".to_string(), - "--set=build.cargo=/does/not/exist".to_string(), - "--config=/does/not/exist".to_string(), - "--skip-stage0-validation".to_string(), - ], - |&_| toml::from_str(&config).unwrap(), - ) + Config::parse_inner(&["check".to_string(), "--config=/does/not/exist".to_string()], |&_| { + toml::from_str(&config).unwrap() + }) } #[test] @@ -212,10 +205,7 @@ fn override_toml_duplicate() { Config::parse_inner( &[ "check".to_owned(), - "--set=build.rustc=/does/not/exist".to_string(), - "--set=build.cargo=/does/not/exist".to_string(), - "--config=/does/not/exist".to_owned(), - "--skip-stage0-validation".to_owned(), + "--config=/does/not/exist".to_string(), "--set=change-id=1".to_owned(), "--set=change-id=2".to_owned(), ], @@ -238,15 +228,7 @@ fn profile_user_dist() { .and_then(|table: toml::Value| TomlConfig::deserialize(table)) .unwrap() } - Config::parse_inner( - &[ - "check".to_owned(), - "--set=build.rustc=/does/not/exist".to_string(), - "--set=build.cargo=/does/not/exist".to_string(), - "--skip-stage0-validation".to_string(), - ], - get_toml, - ); + Config::parse_inner(&["check".to_owned()], get_toml); } #[test] diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 60f48c5923e..2b11b8c3d4f 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -9,11 +9,10 @@ use std::{ }; use build_helper::ci::CiEnv; -use build_helper::stage0_parser::VersionMetadata; use xz2::bufread::XzDecoder; +use crate::utils::helpers::hex_encode; use crate::utils::helpers::{check_run, exe, move_file, program_out_of_date}; -use crate::{core::build_steps::llvm::detect_llvm_sha, utils::helpers::hex_encode}; use crate::{t, Config}; static SHOULD_FIX_BINS_AND_DYLIBS: OnceLock<bool> = OnceLock::new(); @@ -405,9 +404,17 @@ impl Config { cargo_clippy } + #[cfg(feature = "bootstrap-self-test")] + pub(crate) fn maybe_download_rustfmt(&self) -> Option<PathBuf> { + None + } + /// NOTE: rustfmt is a completely different toolchain than the bootstrap compiler, so it can't /// reuse target directories or artifacts + #[cfg(not(feature = "bootstrap-self-test"))] pub(crate) fn maybe_download_rustfmt(&self) -> Option<PathBuf> { + use build_helper::stage0_parser::VersionMetadata; + let VersionMetadata { date, version } = self.stage0_metadata.rustfmt.as_ref()?; let channel = format!("{version}-{date}"); @@ -487,6 +494,10 @@ impl Config { ); } + #[cfg(feature = "bootstrap-self-test")] + pub(crate) fn download_beta_toolchain(&self) {} + + #[cfg(not(feature = "bootstrap-self-test"))] pub(crate) fn download_beta_toolchain(&self) { self.verbose(|| println!("downloading stage0 beta artifacts")); @@ -665,7 +676,13 @@ download-rustc = false self.unpack(&tarball, &bin_root, prefix); } + #[cfg(feature = "bootstrap-self-test")] + pub(crate) fn maybe_download_ci_llvm(&self) {} + + #[cfg(not(feature = "bootstrap-self-test"))] pub(crate) fn maybe_download_ci_llvm(&self) { + use crate::core::build_steps::llvm::detect_llvm_sha; + if !self.llvm_from_ci { return; } @@ -707,6 +724,7 @@ download-rustc = false } } + #[cfg(not(feature = "bootstrap-self-test"))] fn download_ci_llvm(&self, llvm_sha: &str) { let llvm_assertions = self.llvm_assertions; diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 8ffa97ab78b..b5f17b9f54e 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -8,13 +8,19 @@ //! In theory if we get past this phase it's a bug if a build fails, but in //! practice that's likely not true! -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::env; use std::ffi::{OsStr, OsString}; use std::fs; use std::path::PathBuf; use std::process::Command; -use walkdir::WalkDir; + +#[cfg(not(feature = "bootstrap-self-test"))] +use crate::builder::Builder; +#[cfg(not(feature = "bootstrap-self-test"))] +use crate::core::build_steps::tool; +#[cfg(not(feature = "bootstrap-self-test"))] +use std::collections::HashSet; use crate::builder::Kind; use crate::core::config::Target; @@ -31,10 +37,16 @@ pub struct Finder { // it might not yet be included in stage0. In such cases, we handle the targets missing from stage0 in this list. // // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). +#[cfg(not(feature = "bootstrap-self-test"))] const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined ]; +/// Minimum version threshold for libstdc++ required when using prebuilt LLVM +/// from CI (with`llvm.download-ci-llvm` option). +#[cfg(not(feature = "bootstrap-self-test"))] +const LIBSTDCXX_MIN_VERSION_THRESHOLD: usize = 8; + impl Finder { pub fn new() -> Self { Self { cache: HashMap::new(), path: env::var_os("PATH").unwrap_or_default() } @@ -99,6 +111,31 @@ pub fn check(build: &mut Build) { cmd_finder.must_have("git"); } + // Ensure that a compatible version of libstdc++ is available on the system when using `llvm.download-ci-llvm`. + #[cfg(not(feature = "bootstrap-self-test"))] + if !build.config.dry_run() && !build.build.is_msvc() && build.config.llvm_from_ci { + let builder = Builder::new(build); + let libcxx_version = builder.ensure(tool::LibcxxVersionTool { target: build.build }); + + match libcxx_version { + tool::LibcxxVersion::Gnu(version) => { + if LIBSTDCXX_MIN_VERSION_THRESHOLD > version { + eprintln!( + "\nYour system's libstdc++ version is too old for the `llvm.download-ci-llvm` option." + ); + eprintln!("Current version detected: '{}'", version); + eprintln!("Minimum required version: '{}'", LIBSTDCXX_MIN_VERSION_THRESHOLD); + eprintln!( + "Consider upgrading libstdc++ or disabling the `llvm.download-ci-llvm` option." + ); + } + } + tool::LibcxxVersion::Llvm(_) => { + // FIXME: Handle libc++ version check. + } + } + } + // We need cmake, but only if we're actually building LLVM or sanitizers. let building_llvm = build .hosts @@ -167,6 +204,7 @@ than building it. .map(|p| cmd_finder.must_have(p)) .or_else(|| cmd_finder.maybe_have("reuse")); + #[cfg(not(feature = "bootstrap-self-test"))] let stage0_supported_target_list: HashSet<String> = output(Command::new(&build.config.initial_rustc).args(["--print", "target-list"])) .lines() @@ -193,11 +231,11 @@ than building it. continue; } - let target_str = target.to_string(); - // Ignore fake targets that are only used for unit tests in bootstrap. - if !["A-A", "B-B", "C-C"].contains(&target_str.as_str()) { + #[cfg(not(feature = "bootstrap-self-test"))] + { let mut has_target = false; + let target_str = target.to_string(); let missing_targets_hashset: HashSet<_> = STAGE0_MISSING_TARGETS.iter().map(|t| t.to_string()).collect(); @@ -226,7 +264,7 @@ than building it. target_filename.push(".json"); // Recursively traverse through nested directories. - let walker = WalkDir::new(custom_target_path).into_iter(); + let walker = walkdir::WalkDir::new(custom_target_path).into_iter(); for entry in walker.filter_map(|e| e.ok()) { has_target |= entry.file_name() == target_filename; } diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 9af368ef445..824c904e17f 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -233,7 +233,7 @@ For targets: `aarch64-unknown-linux-gnu` - Operating System > Linux kernel version = 4.1.49 - Binary utilities > Version of binutils = 2.29.1 - C-library > glibc version = 2.17 -- aarch64 support was introduced in this version -- C compiler > gcc version = 8.5.0 +- C compiler > gcc version = 13.2.0 - C compiler > C++ = ENABLE -- to cross compile LLVM ### `i586-linux-gnu.defconfig` diff --git a/src/ci/docker/host-x86_64/dist-aarch64-linux/aarch64-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-aarch64-linux/aarch64-linux-gnu.defconfig index 47e984ef85a..520b1667c8b 100644 --- a/src/ci/docker/host-x86_64/dist-aarch64-linux/aarch64-linux-gnu.defconfig +++ b/src/ci/docker/host-x86_64/dist-aarch64-linux/aarch64-linux-gnu.defconfig @@ -6,7 +6,5 @@ CT_ARCH_ARM=y CT_ARCH_64=y CT_KERNEL_LINUX=y CT_LINUX_V_4_1=y -CT_BINUTILS_V_2_29=y CT_GLIBC_V_2_17=y -CT_GCC_V_8=y CT_CC_LANG_CXX=y diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh index 3939b4b7c41..d046b539036 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh @@ -54,7 +54,7 @@ apt-get clean # This makes all those symlinks. for lib in $(find -name '*.so.*'); do target=${lib%.so.*}.so - [ -e $target ] || ln -s ${lib##*/} $target + ln -s ${lib##*/} $target || echo "warning: silenced error symlinking $lib" done # Remove Solaris 11 functions that are optionally used by libbacktrace. diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index d0da7d30660..0d9c21c4487 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -61,8 +61,8 @@ ENV SCRIPT python3 ../x.py check --stage 0 --set build.optimized-compiler-builti /scripts/validate-toolstate.sh && \ /scripts/validate-error-codes.sh && \ reuse --include-submodules lint && \ - # Runs checks to ensure that there are no ES5 issues in our JS code. - es-check es8 ../src/librustdoc/html/static/js/*.js && \ + # Runs checks to ensure that there are no issues in our JS code. + es-check es2019 ../src/librustdoc/html/static/js/*.js && \ eslint -c ../src/librustdoc/html/static/.eslintrc.js ../src/librustdoc/html/static/js/*.js && \ eslint -c ../src/tools/rustdoc-js/.eslintrc.js ../src/tools/rustdoc-js/tester.js && \ eslint -c ../src/tools/rustdoc-gui/.eslintrc.js ../src/tools/rustdoc-gui/tester.js diff --git a/src/ci/docker/host-x86_64/rfl/Dockerfile b/src/ci/docker/host-x86_64/rfl/Dockerfile new file mode 100644 index 00000000000..97298519cf2 --- /dev/null +++ b/src/ci/docker/host-x86_64/rfl/Dockerfile @@ -0,0 +1,40 @@ +FROM ubuntu:22.04 + +ARG DEBIAN_FRONTEND=noninteractive + +# libclang1 is required for libclang.so, required by bindgen +# clang, llvm and lld is required by RfL to compile host code +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + ninja-build \ + file \ + curl \ + ca-certificates \ + python3 \ + git \ + cmake \ + flex \ + bison \ + bc \ + clang-15 \ + libclang1-15 \ + llvm-15 \ + lld-15 \ + libelf-dev \ + libedit-dev \ + libssl-dev \ + pkg-config \ + zlib1g-dev \ + && rm -rf /var/lib/apt/lists/* + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +# RfL needs access to cland, lld and llvm tools +ENV PATH="${PATH}:/usr/lib/llvm-15/bin" + +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu + +COPY /scripts/rfl-build.sh /tmp/rfl-build.sh +ENV SCRIPT bash /tmp/rfl-build.sh diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock index b0c17d9a296..dacf531e404 100644 --- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock +++ b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "r-efi" -version = "4.4.0" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c47196f636c4cc0634b73b0405323d177753c2e15e866952c64ea22902567a34" +checksum = "e9e935efc5854715dfc0a4c9ef18dc69dee0ec3bf9cc3ab740db831c0fdd86a3" [[package]] name = "uefi_qemu_test" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile index e4534d0f840..fa31801269a 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile @@ -44,6 +44,14 @@ ENV RUST_CONFIGURE_ARGS \ --set target.x86_64-unknown-linux-gnu.cc=clang \ --set target.x86_64-unknown-linux-gnu.cxx=clang++ +# This job appears to be checking two separate things: +# - That we can build the compiler with `--enable-debug` +# (without necessarily testing the result). +# - That the tests with `//@ needs-force-clang-based-tests` pass, since they +# don't run by default unless RUSTBUILD_FORCE_CLANG_BASED_TESTS is set. +# - FIXME(https://github.com/rust-lang/rust/pull/126155#issuecomment-2156314273): +# Currently we only run the subset of tests with "clang" in their name. + ENV SCRIPT \ python3 ../x.py --stage 2 build && \ - python3 ../x.py --stage 2 test tests/run-make-fulldeps --test-args clang + python3 ../x.py --stage 2 test tests/run-make --test-args clang diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile index c8c754914aa..d228dfc87eb 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-integration/Dockerfile @@ -1,3 +1,6 @@ +# This job builds a toolchain capable of building Fuchsia, and then builds +# Fuchsia. See the build-fuchsia.sh script in this directory for more details. + FROM ubuntu:22.04 ARG DEBIAN_FRONTEND=noninteractive diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh b/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh index 9cc508fe928..913a0b0c09c 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh @@ -2,50 +2,87 @@ # Downloads and builds the Fuchsia operating system using a toolchain installed # in $RUST_INSTALL_DIR. +# +# You may run this script locally using Docker with the following command: +# +# $ src/ci/docker/run.sh x86_64-gnu-integration +# +# Alternatively, from within the container with --dev, assuming you have made it +# as far as building the toolchain with the above command: +# +# $ src/ci/docker/run.sh --dev x86_64-gnu-integration +# docker# git config --global --add safe.directory /checkout/obj/fuchsia +# docker# ../src/ci/docker/host-x86_64/x86_64-gnu-integration/build-fuchsia.sh +# +# Also see the docs in the rustc-dev-guide for more info: +# https://github.com/rust-lang/rustc-dev-guide/pull/1989 set -euf -o pipefail -INTEGRATION_SHA=1011e3298775ee7cdf6f6dc73e808d6a86e33bd6 +# Set this variable to 1 to disable updating the Fuchsia checkout. This is +# useful for making local changes. You can find the Fuchsia checkout in +# `obj/x86_64-gnu-integration/fuchsia` in your local checkout after running this +# job for the first time. +KEEP_CHECKOUT= + +# Any upstream refs that should be cherry-picked. This can be used to include +# Gerrit changes from https://fxrev.dev during development (click the "Download" +# button on a changelist to see the cherry pick ref). Example: +# PICK_REFS=(refs/changes/71/1054071/2 refs/changes/74/1054574/2) PICK_REFS=() +# The commit hash of Fuchsia's integration.git to check out. This controls the +# commit hash of fuchsia.git and some other repos in the "monorepo" checkout, in +# addition to versions of prebuilts. It should be bumped regularly by the +# Fuchsia team – we aim for every 1-2 months. +INTEGRATION_SHA=1011e3298775ee7cdf6f6dc73e808d6a86e33bd6 + checkout=fuchsia jiri=.jiri_root/bin/jiri set -x -# This script will: -# - create a directory named "fuchsia" if it does not exist -# - download "jiri" to "fuchsia/.jiri_root/bin" -curl -s "https://fuchsia.googlesource.com/jiri/+/HEAD/scripts/bootstrap_jiri?format=TEXT" \ - | base64 --decode \ - | bash -s $checkout - -cd $checkout - -$jiri init \ - -partial=true \ - -analytics-opt=false \ - . - -$jiri import \ - -name=integration \ - -revision=$INTEGRATION_SHA \ - -overwrite=true \ - flower \ - "https://fuchsia.googlesource.com/integration" - -if [ -d ".git" ]; then - # Wipe out any local changes if we're reusing a checkout. - git checkout --force JIRI_HEAD -fi +if [ -z "$KEEP_CHECKOUT" ]; then + # This script will: + # - create a directory named "fuchsia" if it does not exist + # - download "jiri" to "fuchsia/.jiri_root/bin" + curl -s "https://fuchsia.googlesource.com/jiri/+/HEAD/scripts/bootstrap_jiri?format=TEXT" \ + | base64 --decode \ + | bash -s $checkout -$jiri update -autoupdate=false + cd $checkout -echo integration commit = $(git -C integration rev-parse HEAD) + $jiri init \ + -partial=true \ + -analytics-opt=false \ + . -for git_ref in "${PICK_REFS[@]}"; do - git fetch https://fuchsia.googlesource.com/fuchsia $git_ref - git cherry-pick --no-commit FETCH_HEAD -done + $jiri import \ + -name=integration \ + -revision=$INTEGRATION_SHA \ + -overwrite=true \ + flower \ + "https://fuchsia.googlesource.com/integration" + + if [ -d ".git" ]; then + # Wipe out any local changes if we're reusing a checkout. + git checkout --force JIRI_HEAD + fi + + $jiri update -autoupdate=false + + echo integration commit = $(git -C integration rev-parse HEAD) + + for git_ref in "${PICK_REFS[@]}"; do + git fetch https://fuchsia.googlesource.com/fuchsia $git_ref + git cherry-pick --no-commit FETCH_HEAD + done +else + echo Reusing existing Fuchsia checkout + cd $checkout +fi +# Run the script inside the Fuchsia checkout responsible for building Fuchsia. +# You can change arguments to the build by setting KEEP_CHECKOUT=1 above and +# modifying them in build_fuchsia_from_rust_ci.sh. bash scripts/rust/build_fuchsia_from_rust_ci.sh diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 22dcb808c74..a4c59b3067e 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -270,7 +270,6 @@ else args="$args --volume $root_dir:/checkout$SRC_MOUNT_OPTION" args="$args --volume $objdir:/checkout/obj" args="$args --volume $HOME/.cargo:/cargo" - args="$args --volume $HOME/rustsrc:$HOME/rustsrc" args="$args --volume /tmp/toolstate:/tmp/toolstate" id=$(id -u) diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh new file mode 100755 index 00000000000..da7b029ca73 --- /dev/null +++ b/src/ci/docker/scripts/rfl-build.sh @@ -0,0 +1,68 @@ +#!/bin/bash + +set -euo pipefail + +LINUX_VERSION=c13320499ba0efd93174ef6462ae8a7a2933f6e7 + +# Build rustc, rustdoc and cargo +../x.py build --stage 1 library rustdoc +../x.py build --stage 0 cargo + +# Install rustup so that we can use the built toolchain easily, and also +# install bindgen in an easy way. +curl --proto '=https' --tlsv1.2 -sSf -o rustup.sh https://sh.rustup.rs +sh rustup.sh -y --default-toolchain none + +source /cargo/env + +BUILD_DIR=$(realpath ./build) +rustup toolchain link local "${BUILD_DIR}"/x86_64-unknown-linux-gnu/stage1 +rustup default local + +mkdir -p rfl +cd rfl + +# Remove existing directory to make local builds easier +rm -rf linux || true + +# Download Linux at a specific commit +mkdir -p linux +git -C linux init +git -C linux remote add origin https://github.com/torvalds/linux.git +git -C linux fetch --depth 1 origin ${LINUX_VERSION} +git -C linux checkout FETCH_HEAD + +# Install bindgen +"${BUILD_DIR}"/x86_64-unknown-linux-gnu/stage0/bin/cargo install \ + --version $(linux/scripts/min-tool-version.sh bindgen) \ + bindgen-cli + +# Configure Rust for Linux +cat <<EOF > linux/kernel/configs/rfl-for-rust-ci.config +# CONFIG_WERROR is not set + +CONFIG_RUST=y + +CONFIG_SAMPLES=y +CONFIG_SAMPLES_RUST=y + +CONFIG_SAMPLE_RUST_MINIMAL=m +CONFIG_SAMPLE_RUST_PRINT=y + +CONFIG_RUST_PHYLIB_ABSTRACTIONS=y +CONFIG_AX88796B_PHY=y +CONFIG_AX88796B_RUST_PHY=y + +CONFIG_KUNIT=y +CONFIG_RUST_KERNEL_DOCTESTS=y +EOF + +make -C linux LLVM=1 -j$(($(nproc) + 1)) \ + rustavailable \ + defconfig \ + rfl-for-rust-ci.config + +make -C linux LLVM=1 -j$(($(nproc) + 1)) \ + samples/rust/rust_minimal.o \ + samples/rust/rust_print.o \ + drivers/net/phy/ax88796b_rust.o diff --git a/src/ci/docker/scripts/x86_64-gnu-llvm.sh b/src/ci/docker/scripts/x86_64-gnu-llvm.sh index 876b300d35c..b3921f11421 100755 --- a/src/ci/docker/scripts/x86_64-gnu-llvm.sh +++ b/src/ci/docker/scripts/x86_64-gnu-llvm.sh @@ -4,13 +4,7 @@ set -ex # Only run the stage 1 tests on merges, not on PR CI jobs. if [[ -z "${PR_CI_JOB}" ]]; then - # When running gcc backend tests, we need to install `libgccjit` and to not run llvm codegen - # tests as it will fail them. - if [[ "${ENABLE_GCC_CODEGEN}" == "1" ]]; then - ../x.py --stage 1 test --skip src/tools/tidy --skip tests/codegen - else - ../x.py --stage 1 test --skip src/tools/tidy - fi + ../x.py --stage 1 test --skip src/tools/tidy # Run the `mir-opt` tests again but this time for a 32-bit target. # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have @@ -29,14 +23,8 @@ if [[ -z "${PR_CI_JOB}" ]]; then --rustc-args "--cfg feature=\"optimize_for_size\"" fi -# When running gcc backend tests, we need to install `libgccjit` and to not run llvm codegen -# tests as it will fail them. # NOTE: intentionally uses all of `x.py`, `x`, and `x.ps1` to make sure they all work on Linux. -if [[ "${ENABLE_GCC_CODEGEN}" == "1" ]]; then - ../x.py --stage 2 test --skip src/tools/tidy --skip tests/codegen -else - ../x.py --stage 2 test --skip src/tools/tidy -fi +../x.py --stage 2 test --skip src/tools/tidy # Run the `mir-opt` tests again but this time for a 32-bit target. # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index ca86f3f0110..1db763735e6 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -33,11 +33,11 @@ runners: <<: *base-job - &job-aarch64-linux - os: [ self-hosted, ARM64, linux ] + os: ubuntu-22.04-arm64-8core-32gb envs: env-x86_64-apple-tests: &env-x86_64-apple-tests - SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc --skip tests/run-make-fulldeps + SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 MACOSX_DEPLOYMENT_TARGET: 10.12 @@ -58,9 +58,16 @@ envs: CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55 AWS_REGION: us-west-1 + TOOLSTATE_PUBLISH: 1 try: <<: *production + # The following env var activates faster `try` builds in `opt-dist` by, e.g. + # - building only the more commonly useful components (we rarely need e.g. rust-docs in try + # builds) + # - not running `opt-dist`'s post-optimization smoke tests on the resulting toolchain + # + # If you *want* these to happen however, temporarily uncomment it before triggering a try build. DIST_TRY_BUILD: 1 auto: @@ -287,7 +294,7 @@ auto: - image: x86_64-apple-2 env: - SCRIPT: ./x.py --stage 2 test tests/ui tests/rustdoc tests/run-make-fulldeps + SCRIPT: ./x.py --stage 2 test tests/ui tests/rustdoc <<: *env-x86_64-apple-tests <<: *job-macos-xl @@ -458,3 +465,8 @@ auto: RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler SCRIPT: python x.py dist bootstrap --include-default-paths <<: *job-windows-8c + + # Tests integration with Rust for Linux. + # Builds stage 1 compiler and tries to compile a few RfL examples with it. + - image: rfl + <<: *job-linux-8c diff --git a/src/ci/publish_toolstate.sh b/src/ci/publish_toolstate.sh index 691df04e754..e828365c416 100755 --- a/src/ci/publish_toolstate.sh +++ b/src/ci/publish_toolstate.sh @@ -24,8 +24,8 @@ cd rust-toolstate FAILURE=1 for RETRY_COUNT in 1 2 3 4 5; do # The purpose of this is to publish the new "current" toolstate in the toolstate repo. - # This happens post-landing, on master. - # (Publishing the per-commit test results happens pre-landing in src/bootstrap/toolstate.rs). + # This happens at the end of auto builds. + # (Publishing the per-commit test results happens in src/bootstrap/toolstate.rs). "$(ciCheckoutPath)/src/tools/publish_toolstate.py" "$GIT_COMMIT" \ "$GIT_COMMIT_MSG" \ "$MESSAGE_FILE" \ diff --git a/src/doc/book b/src/doc/book -Subproject 85442a608426d3667f1c9458ad457b241a36b56 +Subproject 5228bfac8267ad24659a81b92ec5417976b5edb diff --git a/src/doc/edition-guide b/src/doc/edition-guide -Subproject 0c68e90acaae5a611f8f5098a3c2980de9845ab +Subproject bbaabbe088e21a81a0d9ae6757705020d5d7b41 diff --git a/src/doc/embedded-book b/src/doc/embedded-book -Subproject dd962bb82865a5284f2404e5234f1e3222b9c02 +Subproject b10c6acaf0f43481f6600e95d4b5013446e29f7 diff --git a/src/doc/nomicon b/src/doc/nomicon -Subproject 0d5f88475fe285affa6dbbc806e9e44d730797c +Subproject 0ebdacadbda8ce2cd8fbf93985e15af61a7ab89 diff --git a/src/doc/reference b/src/doc/reference -Subproject e356977fceaa8591c762312d8d446769166d4b3 +Subproject 6019b76f5b28938565b251bbba0bf5cc5c43d86 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject 20482893d1a502df72f76762c97aed88854cdf8 +Subproject 4840dca06cadf48b305d3ce0aeafde7f80933f8 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject b6d4a4940bab85cc91eec70cc2e3096dd48da62 +Subproject 6a7374bd87cbac0f8be4fd4877d8186d9c31398 diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 4ef2fcebe92..201ace5ce3a 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -30,10 +30,15 @@ - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md) - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md) - [arm-none-eabi](platform-support/arm-none-eabi.md) - - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md) - - [armv5te-none-eabi](platform-support/armv5te-none-eabi.md) - - [armv7r-none-eabi](platform-support/armv7r-none-eabi.md) - - [armv8r-none-eabihf](platform-support/armv8r-none-eabihf.md) + - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md) + - [armv5te-none-eabi](platform-support/armv5te-none-eabi.md) + - [armv7r-none-eabi](platform-support/armv7r-none-eabi.md) + - [armv8r-none-eabihf](platform-support/armv8r-none-eabihf.md) + - [thumbv6m-none-eabi](./platform-support/thumbv6m-none-eabi.md) + - [thumbv7em-none-eabi\*](./platform-support/thumbv7em-none-eabi.md) + - [thumbv7m-none-eabi](./platform-support/thumbv7m-none-eabi.md) + - [thumbv8m.base-none-eabi](./platform-support/thumbv8m.base-none-eabi.md) + - [thumbv8m.main-none-eabi\*](./platform-support/thumbv8m.main-none-eabi.md) - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md) - [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md) - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md) @@ -60,11 +65,6 @@ - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) - [riscv32*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md) - [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md) - - [thumbv6m-none-eabi](./platform-support/thumbv6m-none-eabi.md) - - [thumbv7m-none-eabi](./platform-support/thumbv7m-none-eabi.md) - - [thumbv7em-none-eabi\*](./platform-support/thumbv7em-none-eabi.md) - - [thumbv8m.base-none-eabi](./platform-support/thumbv8m.base-none-eabi.md) - - [thumbv8m.main-none-eabi\*](./platform-support/thumbv8m.main-none-eabi.md) - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md) - [\*-nto-qnx-\*](platform-support/nto-qnx.md) - [*-unikraft-linux-musl](platform-support/unikraft-linux-musl.md) diff --git a/src/doc/rustc/src/check-cfg/cargo-specifics.md b/src/doc/rustc/src/check-cfg/cargo-specifics.md index bfa60161926..bd4bebbc874 100644 --- a/src/doc/rustc/src/check-cfg/cargo-specifics.md +++ b/src/doc/rustc/src/check-cfg/cargo-specifics.md @@ -3,12 +3,12 @@ <!-- This page is currently (as of May 2024) the canonical place for describing the interaction between Cargo and --check-cfg. It is placed in the rustc book rather than the Cargo book -since check-cfg is primarely a Rust/rustc feature and is therefor consider by T-cargo to +since check-cfg is primarily a Rust/rustc feature and is therefore considered by T-cargo to be an implementation detail, at least --check-cfg and the unexpected_cfgs are owned by rustc, not Cargo. --> -This document is intented to summarize the principal ways Cargo interacts with +This document is intended to summarize the principal ways Cargo interacts with the `unexpected_cfgs` lint and `--check-cfg` flag. It is not intended to provide individual details, for that refer to the [`--check-cfg` documentation](../check-cfg.md) and to the [Cargo book](../../cargo/index.html). @@ -17,7 +17,7 @@ to the [Cargo book](../../cargo/index.html). *See the [`[features]` section in the Cargo book][cargo-features] for more details.* -With the `[features]` table Cargo provides a mechanism to express conditional compilation and +With the `[features]` table, Cargo provides a mechanism to express conditional compilation and optional dependencies. Cargo *automatically* declares corresponding cfgs for every feature as expected. @@ -32,16 +32,16 @@ my_feature = [] ## `check-cfg` in `[lints.rust]` table -<!-- Note that T-Cargo considers `[lints.rust.unexpected_cfgs.check-cfg]` to be an -implementation detail and is therefor not documented in Cargo, we therefor do that ourself --> +<!-- Note that T-Cargo considers `lints.rust.unexpected_cfgs.check-cfg` to be an +implementation detail and is therefore documented here and not in Cargo. --> *See the [`[lints]` section in the Cargo book][cargo-lints-table] for more details.* -When using a staticlly known custom config (ie. not dependant on a build-script), Cargo provides +When using a statically known custom config (i.e., not dependent on a build-script), Cargo provides the custom lint config `check-cfg` under `[lints.rust.unexpected_cfgs]`. It can be used to set custom static [`--check-cfg`](../check-cfg.md) args, it is mainly useful when -the list of expected cfgs is known is advance. +the list of expected cfgs is known in advance. `Cargo.toml`: ```toml diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 3e1ac2fa8ad..72ab8ab5ce9 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -213,21 +213,39 @@ The valid emit kinds are: `CRATE_NAME.o`. The output filename can be set with the [`-o` flag](#option-o-output). A -suffix may be added to the filename with the [`-C extra-filename` -flag](codegen-options/index.md#extra-filename). The files are written to the -current directory unless the [`--out-dir` flag](#option-out-dir) is used. Each -emission type may also specify the output filename with the form `KIND=PATH`, -which takes precedence over the `-o` flag. -Specifying `-o -` or `--emit KIND=-` asks rustc to emit to stdout. -Text output types (`asm`, `dep-info`, `llvm-ir` and `mir`) can be written to -stdout despite it being a tty or not. This will result in an error if any -binary output type is written to stdout that is a tty. -This will also result in an error if multiple output types -would be written to stdout, because they would be all mixed together. +suffix may be added to the filename with the +[`-C extra-filename` flag](codegen-options/index.md#extra-filename). + +Output files are written to the current directory unless the +[`--out-dir` flag](#option-out-dir) is used. [LLVM bitcode]: https://llvm.org/docs/BitCodeFormat.html [LLVM IR]: https://llvm.org/docs/LangRef.html +### Custom paths for individual emit kinds + +Each emit type can optionally be followed by `=` to specify an explicit output +path that only applies to the output of that type. For example: + +- `--emit=link,dep-info=/path/to/dep-info.d` + - Emit the crate itself as normal, + and also emit dependency info to the specified path. +- `--emit=llvm-ir=-,mir` + - Emit MIR to the default filename (based on crate name), + and emit LLVM IR to stdout. + +### Emitting to stdout + +When using `--emit` or [`-o`](#option-o-output), output can be sent to stdout +by specifying `-` as the path (e.g. `-o -`). + +Binary output types can only be written to stdout if it is not a tty. +Text output types (`asm`, `dep-info`, `llvm-ir` and `mir`) can be written to +stdout regardless of whether it is a tty or not. + +Only one type of output can be written to stdout. Attempting to write multiple +types to stdout at the same time will result in an error. + <a id="option-print"></a> ## `--print`: print compiler information diff --git a/src/doc/rustc/src/json.md b/src/doc/rustc/src/json.md index 32083b2f731..c853f34ee03 100644 --- a/src/doc/rustc/src/json.md +++ b/src/doc/rustc/src/json.md @@ -217,7 +217,8 @@ Diagnostics have the following format: Artifact notifications are emitted when the [`--json=artifacts` flag][option-json] is used. They indicate that a file artifact has been saved to disk. More information about emit kinds may be found in the [`--emit` -flag][option-emit] documentation. +flag][option-emit] documentation. Notifications can contain more than one file +for each type, for example when using multiple codegen units. ```javascript { @@ -229,6 +230,11 @@ flag][option-emit] documentation. - "link": The generated crate as specified by the crate-type. - "dep-info": The `.d` file with dependency information in a Makefile-like syntax. - "metadata": The Rust `.rmeta` file containing metadata about the crate. + - "asm": The `.s` file with generated assembly + - "llvm-ir": The `.ll` file with generated textual LLVM IR + - "llvm-bc": The `.bc` file with generated LLVM bitcode + - "mir": The `.mir` file with rustc's mid-level intermediate representation. + - "obj": The `.o` file with generated native object code */ "emit": "link" } diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 77859956c95..633c26a4f56 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -33,12 +33,12 @@ All tier 1 targets with host tools support the full standard library. target | notes -------|------- `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+) -`i686-pc-windows-gnu` | 32-bit MinGW (Windows 10+) [^x86_32-floats-return-ABI] -`i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+) [^x86_32-floats-return-ABI] +`i686-pc-windows-gnu` | 32-bit MinGW (Windows 10+, Windows Server 2016+) [^x86_32-floats-return-ABI] +`i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+) [^x86_32-floats-return-ABI] `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+) [^x86_32-floats-return-ABI] [`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+) -`x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 10+) -`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 10+) +`x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 10+, Windows Server 2016+) +`x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 10+, Windows Server 2016+) `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+) [^x86_32-floats-return-ABI]: Due to limitations of the C ABI, floating-point support on `i686` targets is non-compliant: floating-point return values are passed via an x87 register, so NaN payload bits can be lost. See [issue #114479][x86-32-float-issue]. diff --git a/src/doc/rustc/src/platform-support/arm-none-eabi.md b/src/doc/rustc/src/platform-support/arm-none-eabi.md index 0b1b10e4762..de0ef322fa6 100644 --- a/src/doc/rustc/src/platform-support/arm-none-eabi.md +++ b/src/doc/rustc/src/platform-support/arm-none-eabi.md @@ -1,6 +1,15 @@ # `{arm,thumb}*-none-eabi(hf)?` -## Tier 2 Target List +## Common Target Details + +This documentation covers details that apply to a range of bare-metal targets +for 32-bit Arm CPUs. The `arm-none-eabi` flavor of the GNU compiler toolchain is +often used to assist compilation to these targets. + +Details that apply only to only a specific target in this group are covered in +their own document. + +### Tier 2 Target List - Arm A-Profile Architectures - `armv7a-none-eabi` @@ -16,7 +25,7 @@ - *Legacy* Arm Architectures - None -## Tier 3 Target List +### Tier 3 Target List - Arm A-Profile Architectures - `armv7a-none-eabihf` @@ -28,24 +37,21 @@ - [`armv4t-none-eabi` and `thumbv4t-none-eabi`](armv4t-none-eabi.md) - [`armv5te-none-eabi` and `thumbv5te-none-eabi`](armv5te-none-eabi.md) -## Common Target Details - -This documentation covers details that apply to a range of bare-metal targets -for 32-bit Arm CPUs. In addition, target specific details may be covered in -their own document. +## Instruction Sets There are two 32-bit instruction set architectures (ISAs) defined by Arm: - The [*A32 ISA*][a32-isa], with fixed-width 32-bit instructions. Previously - known as the *Arm* ISA, this originated with the original ARM1 of 1985 and has + known as the *Arm* ISA, this originated with the original Arm1 of 1985 and has been updated by various revisions to the architecture specifications ever since. - The [*T32 ISA*][t32-isa], with a mix of 16-bit and 32-bit width instructions. Note that this term includes both the original 16-bit width *Thumb* ISA introduced with the Armv4T architecture in 1994, and the later 16/32-bit sized - *Thumb-2* ISA introduced with the Armv6T2 architecture in 2003. Again, these - ISAs have been revised by subsequent revisions to the relevant Arm - architecture specifications. + *Thumb-2* ISA introduced with the Armv6T2 architecture in 2003. + +Again, these ISAs have been revised by subsequent revisions to the relevant Arm +architecture specifications. There is also a 64-bit ISA with fixed-width 32-bit instructions called the *A64 ISA*, but targets which implement that instruction set generally start with diff --git a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md index f4c8dd46f1d..0c5129d0efb 100644 --- a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md +++ b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md @@ -1,20 +1,18 @@ -# armv4t-none-eabi +# armv4t-none-eabi / thumbv4t-none-eabi Tier 3 -Bare-metal target for any cpu in the Armv4T architecture family, supporting -ARM/Thumb code interworking (aka `A32`/`T32`), with ARM code as the default code -generation. +These two targets are part of the [`arm-none-eabi`](arm-none-eabi.md) target +group, and all the information there applies. -In particular this supports the Game Boy Advance (GBA), but there's nothing -GBA-specific with this target, so any Armv4T device should work fine. - -See [`arm-none-eabi`](arm-none-eabi.md) for information applicable to all -`arm-none-eabi` targets. +Both of these targets can be used on the Game Boy Advance (GBA), among other +things. On the GBA, one should usually use the `thumb` target to get the best +overall performance. ## Target Maintainers * [@Lokathor](https://github.com/lokathor) +* [@corwinkuiper](https://github.com/corwinkuiper) ## Testing @@ -23,6 +21,6 @@ This is a cross-compiled target that you will need to emulate during testing. Because this is a device-agnostic target, and the exact emulator that you'll need depends on the specific device you want to run your code on. -For example, when programming for the Gameboy Advance, the -[mgba-test-runner](https://github.com/agbrs/agb) program could be used to make a -normal set of rust tests be run within the `mgba` emulator. +* When building for the GBA, [mgba-test-runner](https://github.com/agbrs/agb) + can be used to make a normal set of rust tests be run within the `mgba` + emulator. diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index 3e1db692f50..5643c6a0188 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -10,9 +10,9 @@ updatable, and performant. The [Fuchsia team]: - Tyler Mandry ([@tmandry](https://github.com/tmandry)) -- Dan Johnson ([@computerdruid](https://github.com/computerdruid)) - David Koloski ([@djkoloski](https://github.com/djkoloski)) -- Joseph Ryan ([@P1n3appl3](https://github.com/P1n3appl3)) +- Julia Ryan ([@P1n3appl3](https://github.com/P1n3appl3)) +- Erick Tryzelaar ([@erickt](https://github.com/erickt)) As the team evolves over time, the specific members listed here may differ from the members reported by the API. The API should be considered to be diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 56070c2ec34..51a397a38d2 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -160,8 +160,7 @@ export exclude_tests=' --exclude src/tools/linkchecker --exclude tests/ui-fulldeps --exclude rustc - --exclude rustdoc - --exclude tests/run-make-fulldeps' + --exclude rustdoc' env $build_env \ ./x.py test \ diff --git a/src/doc/unstable-book/src/compiler-flags/codegen-backend.md b/src/doc/unstable-book/src/compiler-flags/codegen-backend.md index 67634be6993..7e4be9841f4 100644 --- a/src/doc/unstable-book/src/compiler-flags/codegen-backend.md +++ b/src/doc/unstable-book/src/compiler-flags/codegen-backend.md @@ -12,8 +12,9 @@ backend. The library must be of crate type `dylib` and must contain a function named `__rustc_codegen_backend` with a signature of `fn() -> Box<dyn rustc_codegen_ssa::traits::CodegenBackend>`. ## Example -See also the [`hotplug_codegen_backend`](https://github.com/rust-lang/rust/tree/master/tests/run-make-fulldeps/hotplug_codegen_backend) test -for a full example. +See also the [`codegen-backend/hotplug`] test for a working example. + +[`codegen-backend/hotplug`]: https://github.com/rust-lang/rust/tree/master/tests/ui-fulldeps/codegen-backend/hotplug.rs ```rust,ignore (partial-example) use rustc_codegen_ssa::traits::CodegenBackend; diff --git a/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md index e55165b5374..ab63c986e85 100644 --- a/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md +++ b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md @@ -1,6 +1,6 @@ # `print=check-cfg` -The tracking issue for this feature is: [#XXXXXX](https://github.com/rust-lang/rust/issues/XXXXXX). +The tracking issue for this feature is: [#125704](https://github.com/rust-lang/rust/issues/125704). ------------------------ @@ -15,6 +15,7 @@ This print option works similarly to `--print=cfg` (modulo check-cfg specifics): - `cfg(feature, values("foo", "bar"))`: `feature="foo"` and `feature="bar"` - `cfg(feature, values(none(), ""))`: `feature` and `feature=""` - `cfg(feature, values(any()))`: `feature=any()` + - `cfg(feature, values())`: `feature=` - `cfg(any())`: `any()` - *nothing*: `any()=any()` diff --git a/src/doc/unstable-book/src/language-features/abi-vectorcall.md b/src/doc/unstable-book/src/language-features/abi-vectorcall.md new file mode 100644 index 00000000000..56273bfdb79 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/abi-vectorcall.md @@ -0,0 +1,19 @@ +# `abi_vectorcall` + +The tracking issue for this feature is: [#124485] + +[#124485]: https://github.com/rust-lang/rust/issues/124485 + +------------------------ + +Adds support for the Windows `"vectorcall"` ABI, the equivalent of `__vectorcall` in MSVC. + +```rust,ignore (only-windows-or-x86-or-x86-64) +extern "vectorcall" { + fn add_f64s(x: f64, y: f64) -> f64; +} + +fn main() { + println!("{}", add_f64s(2.0, 4.0)); +} +``` diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index 20bcf1abf41..2857f74c744 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -1,6 +1,6 @@ use super::*; -use rustc_ast::{MetaItemLit, Path, StrStyle}; +use rustc_ast::{MetaItemLit, Path, Safety, StrStyle}; use rustc_span::create_default_session_globals_then; use rustc_span::symbol::{kw, Ident}; use rustc_span::DUMMY_SP; @@ -16,6 +16,7 @@ fn name_value_cfg(name: &str, value: &str) -> Cfg { fn dummy_meta_item_word(name: &str) -> MetaItem { MetaItem { + unsafety: Safety::Default, path: Path::from_ident(Ident::from_str(name)), kind: MetaItemKind::Word, span: DUMMY_SP, @@ -25,6 +26,7 @@ fn dummy_meta_item_word(name: &str) -> MetaItem { fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> MetaItem { let lit = MetaItemLit { symbol, suffix: None, kind, span: DUMMY_SP }; MetaItem { + unsafety: Safety::Default, path: Path::from_ident(Ident::from_str(name)), kind: MetaItemKind::NameValue(lit), span: DUMMY_SP, @@ -34,6 +36,7 @@ fn dummy_meta_item_name_value(name: &str, symbol: Symbol, kind: LitKind) -> Meta macro_rules! dummy_meta_item_list { ($name:ident, [$($list:ident),* $(,)?]) => { MetaItem { + unsafety: Safety::Default, path: Path::from_ident(Ident::from_str(stringify!($name))), kind: MetaItemKind::List(thin_vec![ $( @@ -48,6 +51,7 @@ macro_rules! dummy_meta_item_list { ($name:ident, [$($list:expr),* $(,)?]) => { MetaItem { + unsafety: Safety::Default, path: Path::from_ident(Ident::from_str(stringify!($name))), kind: MetaItemKind::List(thin_vec![ $( diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index c7366ce1a68..0024e246ef0 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -130,7 +130,10 @@ pub(crate) fn try_inline( } Res::Def(DefKind::Const, did) => { record_extern_fqn(cx, did, ItemType::Constant); - cx.with_param_env(did, |cx| clean::ConstantItem(build_const(cx, did))) + cx.with_param_env(did, |cx| { + let (generics, ty, ct) = build_const_item(cx, did); + clean::ConstantItem(generics, Box::new(ty), ct) + }) } Res::Def(DefKind::Macro(kind), did) => { let is_doc_hidden = cx.tcx.is_doc_hidden(did) @@ -717,21 +720,20 @@ pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String { } } -fn build_const(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant { +fn build_const_item( + cx: &mut DocContext<'_>, + def_id: DefId, +) -> (clean::Generics, clean::Type, clean::Constant) { let mut generics = clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id)); clean::simplify::move_bounds_to_generic_parameters(&mut generics); - - clean::Constant { - type_: Box::new(clean_middle_ty( - ty::Binder::dummy(cx.tcx.type_of(def_id).instantiate_identity()), - cx, - Some(def_id), - None, - )), - generics, - kind: clean::ConstantKind::Extern { def_id }, - } + let ty = clean_middle_ty( + ty::Binder::dummy(cx.tcx.type_of(def_id).instantiate_identity()), + cx, + None, + None, + ); + (generics, ty, clean::Constant { kind: clean::ConstantKind::Extern { def_id } }) } fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::Static { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 839bfdf44af..2dcbbf0d150 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -283,31 +283,17 @@ fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> pub(crate) fn clean_const<'tcx>( constant: &hir::ConstArg<'_>, - cx: &mut DocContext<'tcx>, + _cx: &mut DocContext<'tcx>, ) -> Constant { - let def_id = cx.tcx.hir().body_owner_def_id(constant.value.body).to_def_id(); - Constant { - type_: Box::new(clean_middle_ty( - ty::Binder::dummy(cx.tcx.type_of(def_id).instantiate_identity()), - cx, - Some(def_id), - None, - )), - generics: Generics::default(), - kind: ConstantKind::Anonymous { body: constant.value.body }, - } + Constant { kind: ConstantKind::Anonymous { body: constant.value.body } } } pub(crate) fn clean_middle_const<'tcx>( constant: ty::Binder<'tcx, ty::Const<'tcx>>, - cx: &mut DocContext<'tcx>, + _cx: &mut DocContext<'tcx>, ) -> Constant { // FIXME: instead of storing the stringified expression, store `self` directly instead. - Constant { - type_: Box::new(clean_middle_ty(constant.map_bound(|c| c.ty()), cx, None, None)), - generics: Generics::default(), - kind: ConstantKind::TyConst { expr: constant.skip_binder().to_string().into() }, - } + Constant { kind: ConstantKind::TyConst { expr: constant.skip_binder().to_string().into() } } } pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Lifetime> { @@ -2738,11 +2724,11 @@ fn clean_maybe_renamed_item<'tcx>( ItemKind::Static(ty, mutability, body_id) => { StaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: Some(body_id) }) } - ItemKind::Const(ty, generics, body_id) => ConstantItem(Constant { - type_: Box::new(clean_ty(ty, cx)), - generics: clean_generics(generics, cx), - kind: ConstantKind::Local { body: body_id, def_id }, - }), + ItemKind::Const(ty, generics, body_id) => ConstantItem( + clean_generics(generics, cx), + Box::new(clean_ty(ty, cx)), + Constant { kind: ConstantKind::Local { body: body_id, def_id } }, + ), ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy { bounds: ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), generics: clean_generics(ty.generics, cx), @@ -3089,7 +3075,9 @@ fn clean_maybe_renamed_foreign_item<'tcx>( let def_id = item.owner_id.to_def_id(); cx.with_param_env(def_id, |cx| { let kind = match item.kind { - hir::ForeignItemKind::Fn(decl, names, generics) => { + // FIXME(missing_unsafe_on_extern) handle safety of foreign fns. + // Safety was added as part of the implementation of unsafe extern blocks PR #124482 + hir::ForeignItemKind::Fn(decl, names, generics, _) => { let (generics, decl) = enter_impl_trait(cx, |cx| { // NOTE: generics must be cleaned before args let generics = clean_generics(generics, cx); @@ -3099,7 +3087,9 @@ fn clean_maybe_renamed_foreign_item<'tcx>( }); ForeignFunctionItem(Box::new(Function { decl, generics })) } - hir::ForeignItemKind::Static(ty, mutability) => { + // FIXME(missing_unsafe_on_extern) handle safety of foreign statics. + // Safety was added as part of the implementation of unsafe extern blocks PR #124482 + hir::ForeignItemKind::Static(ty, mutability, _) => { ForeignStaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: None }) } hir::ForeignItemKind::Type => ForeignTypeItem, diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs index 5ac1b742c38..995919f73f8 100644 --- a/src/librustdoc/clean/render_macro_matchers.rs +++ b/src/librustdoc/clean/render_macro_matchers.rs @@ -65,7 +65,7 @@ fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String let psess = ParseSess::new(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec()); let file_name = source_map.span_to_filename(span); let mut parser = - match rustc_parse::maybe_new_parser_from_source_str(&psess, file_name, snippet.clone()) { + match rustc_parse::new_parser_from_source_str(&psess, file_name, snippet.clone()) { Ok(parser) => parser, Err(errs) => { errs.into_iter().for_each(|err| err.cancel()); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 3f84da310dd..69678b727c1 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -830,7 +830,6 @@ pub(crate) enum ItemKind { TypeAliasItem(Box<TypeAlias>), OpaqueTyItem(OpaqueTy), StaticItem(Static), - ConstantItem(Constant), TraitItem(Box<Trait>), TraitAliasItem(TraitAlias), ImplItem(Box<Impl>), @@ -853,6 +852,7 @@ pub(crate) enum ItemKind { PrimitiveItem(PrimitiveType), /// A required associated constant in a trait declaration. TyAssocConstItem(Generics, Box<Type>), + ConstantItem(Generics, Box<Type>, Constant), /// An associated constant in a trait impl or a provided one in a trait declaration. AssocConstItem(Generics, Box<Type>, ConstantKind), /// A required associated type in a trait declaration. @@ -888,7 +888,7 @@ impl ItemKind { | TypeAliasItem(_) | OpaqueTyItem(_) | StaticItem(_) - | ConstantItem(_) + | ConstantItem(_, _, _) | TraitAliasItem(_) | TyMethodItem(_) | MethodItem(_, _) @@ -922,7 +922,7 @@ impl ItemKind { | TypeAliasItem(_) | OpaqueTyItem(_) | StaticItem(_) - | ConstantItem(_) + | ConstantItem(_, _, _) | TraitAliasItem(_) | ForeignFunctionItem(_) | ForeignStaticItem(_) @@ -1451,7 +1451,7 @@ impl Trait { tcx.trait_def(self.def_id).safety } pub(crate) fn is_object_safe(&self, tcx: TyCtxt<'_>) -> bool { - tcx.check_is_object_safe(self.def_id) + tcx.is_object_safe(self.def_id) } } @@ -1936,7 +1936,7 @@ impl PrimitiveType { let mut primitive_locations = FxHashMap::default(); // NOTE: technically this misses crates that are only passed with `--extern` and not loaded when checking the crate. // This is a degenerate case that I don't plan to support. - for &crate_num in tcx.crates_including_speculative(()) { + for &crate_num in tcx.crates(()) { let e = ExternalCrate { crate_num }; let crate_name = e.name(tcx); debug!(?crate_num, ?crate_name); @@ -2364,8 +2364,6 @@ pub(crate) struct Static { #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub(crate) struct Constant { - pub(crate) type_: Box<Type>, - pub(crate) generics: Generics, pub(crate) kind: ConstantKind, } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 24a01414c70..7c83d438719 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -353,8 +353,8 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String { s } // array lengths are obviously usize - ty::ConstKind::Value(ty::ValTree::Leaf(scalar)) - if *n.ty().kind() == ty::Uint(ty::UintTy::Usize) => + ty::ConstKind::Value(ty, ty::ValTree::Leaf(scalar)) + if *ty.kind() == ty::Uint(ty::UintTy::Usize) => { scalar.to_string() } @@ -431,8 +431,7 @@ fn print_const_with_custom_print_scalar<'tcx>( (mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Int(i)) => { let ty = ct.ty(); let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size; - let data = int.assert_bits(size); - let sign_extended_data = size.sign_extend(data) as i128; + let sign_extended_data = int.assert_scalar_int().to_int(size); let mut output = if with_underscores { format_integer_with_underscore_sep(&sign_extended_data.to_string()) } else { diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 012afada1e5..78d4129f642 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -128,6 +128,8 @@ pub(crate) struct Options { pub(crate) enable_per_target_ignores: bool, /// Do not run doctests, compile them if should_test is active. pub(crate) no_run: bool, + /// What sources are being mapped. + pub(crate) remap_path_prefix: Vec<(PathBuf, PathBuf)>, /// The path to a rustc-like binary to build tests with. If not set, we /// default to loading from `$sysroot/bin/rustc`. @@ -211,6 +213,7 @@ impl fmt::Debug for Options { .field("run_check", &self.run_check) .field("no_run", &self.no_run) .field("test_builder_wrappers", &self.test_builder_wrappers) + .field("remap-file-prefix", &self.remap_path_prefix) .field("nocapture", &self.nocapture) .field("scrape_examples_options", &self.scrape_examples_options) .field("unstable_features", &self.unstable_features) @@ -372,6 +375,13 @@ impl Options { let codegen_options = CodegenOptions::build(early_dcx, matches); let unstable_opts = UnstableOptions::build(early_dcx, matches); + let remap_path_prefix = match parse_remap_path_prefix(&matches) { + Ok(prefix_mappings) => prefix_mappings, + Err(err) => { + early_dcx.early_fatal(err); + } + }; + let dcx = new_dcx(error_format, None, diagnostic_width, &unstable_opts); // check for deprecated options @@ -772,6 +782,7 @@ impl Options { run_check, no_run, test_builder_wrappers, + remap_path_prefix, nocapture, crate_name, output_format, @@ -820,6 +831,21 @@ impl Options { } } +fn parse_remap_path_prefix( + matches: &getopts::Matches, +) -> Result<Vec<(PathBuf, PathBuf)>, &'static str> { + matches + .opt_strs("remap-path-prefix") + .into_iter() + .map(|remap| { + remap + .rsplit_once('=') + .ok_or("--remap-path-prefix must contain '=' between FROM and TO") + .map(|(from, to)| (PathBuf::from(from), PathBuf::from(to))) + }) + .collect() +} + /// Prints deprecation warnings for deprecated options fn check_deprecated_options(matches: &getopts::Matches, dcx: &rustc_errors::DiagCtxt) { let deprecated_flags = []; diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index ccd5dadb20a..ce098a1bcfb 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -347,7 +347,7 @@ pub(crate) fn run_global_ctxt( show_coverage, }; - for cnum in tcx.crates_including_speculative(()) { + for cnum in tcx.crates(()) { crate::visit_lib::lib_embargo_visit_item(&mut ctxt, cnum.as_def_id()); } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index a536a713921..81a7463deca 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1,27 +1,23 @@ +mod make; +mod markdown; +mod rust; + +pub(crate) use make::make_test; +pub(crate) use markdown::test as test_markdown; + use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync::Lrc; -use rustc_errors::emitter::stderr_destination; use rustc_errors::{ColorConfig, ErrorGuaranteed, FatalError}; -use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; -use rustc_hir::{self as hir, intravisit, CRATE_HIR_ID}; +use rustc_hir::def_id::LOCAL_CRATE; +use rustc_hir::CRATE_HIR_ID; use rustc_interface::interface; -use rustc_middle::hir::map::Map; -use rustc_middle::hir::nested_filter; -use rustc_middle::ty::TyCtxt; -use rustc_parse::maybe_new_parser_from_source_str; -use rustc_parse::parser::attr::InnerAttrPolicy; -use rustc_resolve::rustdoc::span_of_fragments; use rustc_session::config::{self, CrateType, ErrorOutputType}; -use rustc_session::parse::ParseSess; -use rustc_session::{lint, Session}; +use rustc_session::lint; use rustc_span::edition::Edition; -use rustc_span::source_map::SourceMap; use rustc_span::symbol::sym; -use rustc_span::{BytePos, FileName, Pos, Span, DUMMY_SP}; +use rustc_span::FileName; use rustc_target::spec::{Target, TargetTriple}; -use std::env; use std::fs::File; use std::io::{self, Write}; use std::panic; @@ -33,14 +29,17 @@ use std::sync::{Arc, Mutex}; use tempfile::{Builder as TempFileBuilder, TempDir}; -use crate::clean::{types::AttributesExt, Attributes}; use crate::config::Options as RustdocOptions; -use crate::html::markdown::{self, ErrorCodes, Ignore, LangString}; +use crate::html::markdown::{ErrorCodes, Ignore, LangString, MdRelLine}; use crate::lint::init_lints; +use self::rust::HirCollector; + /// Options that apply to all doctests in a crate or Markdown file (for `rustdoc foo.md`). -#[derive(Clone, Default)] +#[derive(Clone)] pub(crate) struct GlobalTestOptions { + /// Name of the crate (for regular `rustdoc`) or Markdown file (for `rustdoc foo.md`). + pub(crate) crate_name: String, /// Whether to disable the default `extern crate my_crate;` when creating doctests. pub(crate) no_crate_inject: bool, /// Whether inserting extra indent spaces in code block, @@ -48,6 +47,8 @@ pub(crate) struct GlobalTestOptions { pub(crate) insert_indent_space: bool, /// Additional crate-level attributes to add to doctests. pub(crate) attrs: Vec<String>, + /// Path to file containing arguments for the invocation of rustc. + pub(crate) args_file: PathBuf, } pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) -> Result<(), String> { @@ -80,7 +81,7 @@ pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) -> let content = content.join("\n"); - file.write(content.as_bytes()) + file.write_all(content.as_bytes()) .map_err(|error| format!("failed to write arguments to temporary file: {error:?}"))?; Ok(()) } @@ -128,6 +129,7 @@ pub(crate) fn run( edition: options.edition, target_triple: options.target.clone(), crate_name: options.crate_name.clone(), + remap_path_prefix: options.remap_path_prefix.clone(), ..config::Options::default() }; @@ -166,43 +168,28 @@ pub(crate) fn run( Ok(temp_dir) => temp_dir, Err(error) => return crate::wrap_return(dcx, Err(error)), }; - let file_path = temp_dir.path().join("rustdoc-cfgs"); - crate::wrap_return(dcx, generate_args_file(&file_path, &options))?; + let args_path = temp_dir.path().join("rustdoc-cfgs"); + crate::wrap_return(dcx, generate_args_file(&args_path, &options))?; let (tests, unused_extern_reports, compiling_test_count) = interface::run_compiler(config, |compiler| { compiler.enter(|queries| { let collector = queries.global_ctxt()?.enter(|tcx| { + let crate_name = tcx.crate_name(LOCAL_CRATE).to_string(); let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID); - - let opts = scrape_test_config(crate_attrs); + let opts = scrape_test_config(crate_name, crate_attrs, args_path); let enable_per_target_ignores = options.enable_per_target_ignores; - let mut collector = Collector::new( - tcx.crate_name(LOCAL_CRATE).to_string(), - options, - false, - opts, - Some(compiler.sess.psess.clone_source_map()), - None, - enable_per_target_ignores, - file_path, - ); - let mut hir_collector = HirCollector { - sess: &compiler.sess, - collector: &mut collector, - map: tcx.hir(), - codes: ErrorCodes::from( - compiler.sess.opts.unstable_features.is_nightly_build(), - ), + let mut collector = CreateRunnableDoctests::new(options, opts); + let hir_collector = HirCollector::new( + &compiler.sess, + tcx.hir(), + ErrorCodes::from(compiler.sess.opts.unstable_features.is_nightly_build()), + enable_per_target_ignores, tcx, - }; - hir_collector.visit_testable( - "".to_string(), - CRATE_DEF_ID, - tcx.hir().span(CRATE_HIR_ID), - |this| tcx.hir().walk_toplevel_module(this), ); + let tests = hir_collector.collect_crate(); + tests.into_iter().for_each(|t| collector.add_test(t)); collector }); @@ -273,11 +260,20 @@ pub(crate) fn run_tests( } // Look for `#![doc(test(no_crate_inject))]`, used by crates in the std facade. -fn scrape_test_config(attrs: &[ast::Attribute]) -> GlobalTestOptions { +fn scrape_test_config( + crate_name: String, + attrs: &[ast::Attribute], + args_file: PathBuf, +) -> GlobalTestOptions { use rustc_ast_pretty::pprust; - let mut opts = - GlobalTestOptions { no_crate_inject: false, attrs: Vec::new(), insert_indent_space: false }; + let mut opts = GlobalTestOptions { + crate_name, + no_crate_inject: false, + attrs: Vec::new(), + insert_indent_space: false, + args_file, + }; let test_attrs: Vec<_> = attrs .iter() @@ -370,30 +366,25 @@ fn wrapped_rustc_command(rustc_wrappers: &[PathBuf], rustc_binary: &Path) -> Com command } +struct RunnableDoctest { + full_test_code: String, + full_test_line_offset: usize, + test_opts: IndividualTestOptions, + global_opts: GlobalTestOptions, + scraped_test: ScrapedDoctest, +} + fn run_test( - test: &str, - crate_name: &str, - line: usize, - rustdoc_options: IndividualTestOptions, - mut lang_string: LangString, - no_run: bool, - opts: &GlobalTestOptions, - edition: Edition, - path: PathBuf, + doctest: RunnableDoctest, + rustdoc_options: &RustdocOptions, + supports_color: bool, report_unused_externs: impl Fn(UnusedExterns), ) -> Result<(), TestFailure> { - let (test, line_offset, supports_color) = make_test( - test, - Some(crate_name), - lang_string.test_harness, - opts, - edition, - Some(&rustdoc_options.test_id), - ); - + let scraped_test = &doctest.scraped_test; + let langstr = &scraped_test.langstr; // Make sure we emit well-formed executable names for our target. let rust_out = add_exe_suffix("rust_out".to_owned(), &rustdoc_options.target); - let output_file = rustdoc_options.outdir.path().join(rust_out); + let output_file = doctest.test_opts.outdir.path().join(rust_out); let rustc_binary = rustdoc_options .test_builder @@ -401,33 +392,41 @@ fn run_test( .unwrap_or_else(|| rustc_interface::util::rustc_path().expect("found rustc")); let mut compiler = wrapped_rustc_command(&rustdoc_options.test_builder_wrappers, rustc_binary); - compiler.arg(&format!("@{}", rustdoc_options.arg_file.display())); + compiler.arg(&format!("@{}", doctest.global_opts.args_file.display())); if let Some(sysroot) = &rustdoc_options.maybe_sysroot { compiler.arg(format!("--sysroot={}", sysroot.display())); } - compiler.arg("--edition").arg(&edition.to_string()); - compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", path); - compiler.env("UNSTABLE_RUSTDOC_TEST_LINE", format!("{}", line as isize - line_offset as isize)); + compiler.arg("--edition").arg(&scraped_test.edition(rustdoc_options).to_string()); + compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", &doctest.test_opts.path); + compiler.env( + "UNSTABLE_RUSTDOC_TEST_LINE", + format!("{}", scraped_test.line as isize - doctest.full_test_line_offset as isize), + ); compiler.arg("-o").arg(&output_file); - if lang_string.test_harness { + if langstr.test_harness { compiler.arg("--test"); } - if rustdoc_options.is_json_unused_externs_enabled && !lang_string.compile_fail { + if rustdoc_options.json_unused_externs.is_enabled() && !langstr.compile_fail { compiler.arg("--error-format=json"); compiler.arg("--json").arg("unused-externs"); compiler.arg("-W").arg("unused_crate_dependencies"); compiler.arg("-Z").arg("unstable-options"); } - if no_run && !lang_string.compile_fail && rustdoc_options.should_persist_doctests { + if scraped_test.no_run(rustdoc_options) + && !langstr.compile_fail + && rustdoc_options.persist_doctests.is_none() + { + // FIXME: why does this code check if it *shouldn't* persist doctests + // -- shouldn't it be the negation? compiler.arg("--emit=metadata"); } - compiler.arg("--target").arg(match rustdoc_options.target { + compiler.arg("--target").arg(match &rustdoc_options.target { TargetTriple::TargetTriple(s) => s, TargetTriple::TargetJson { path_for_rustdoc, .. } => { - path_for_rustdoc.to_str().expect("target path must be valid unicode").to_string() + path_for_rustdoc.to_str().expect("target path must be valid unicode") } }); if let ErrorOutputType::HumanReadable(kind) = rustdoc_options.error_format { @@ -459,7 +458,7 @@ fn run_test( let mut child = compiler.spawn().expect("Failed to spawn rustc process"); { let stdin = child.stdin.as_mut().expect("Failed to open stdin"); - stdin.write_all(test.as_bytes()).expect("could write out test sources"); + stdin.write_all(doctest.full_test_code.as_bytes()).expect("could write out test sources"); } let output = child.wait_with_output().expect("Failed to read stdout"); @@ -490,20 +489,26 @@ fn run_test( } let _bomb = Bomb(&out); - match (output.status.success(), lang_string.compile_fail) { + match (output.status.success(), langstr.compile_fail) { (true, true) => { return Err(TestFailure::UnexpectedCompilePass); } (true, false) => {} (false, true) => { - if !lang_string.error_codes.is_empty() { + if !langstr.error_codes.is_empty() { // We used to check if the output contained "error[{}]: " but since we added the // colored output, we can't anymore because of the color escape characters before // the ":". - lang_string.error_codes.retain(|err| !out.contains(&format!("error[{err}]"))); - - if !lang_string.error_codes.is_empty() { - return Err(TestFailure::MissingErrorCodes(lang_string.error_codes)); + let missing_codes: Vec<String> = scraped_test + .langstr + .error_codes + .iter() + .filter(|err| !out.contains(&format!("error[{err}]"))) + .cloned() + .collect(); + + if !missing_codes.is_empty() { + return Err(TestFailure::MissingErrorCodes(missing_codes)); } } } @@ -512,7 +517,7 @@ fn run_test( } } - if no_run { + if scraped_test.no_run(rustdoc_options) { return Ok(()); } @@ -520,15 +525,15 @@ fn run_test( let mut cmd; let output_file = make_maybe_absolute_path(output_file); - if let Some(tool) = rustdoc_options.runtool { + if let Some(tool) = &rustdoc_options.runtool { let tool = make_maybe_absolute_path(tool.into()); cmd = Command::new(tool); - cmd.args(rustdoc_options.runtool_args); + cmd.args(&rustdoc_options.runtool_args); cmd.arg(output_file); } else { cmd = Command::new(output_file); } - if let Some(run_directory) = rustdoc_options.test_run_directory { + if let Some(run_directory) = &rustdoc_options.test_run_directory { cmd.current_dir(run_directory); } @@ -544,9 +549,9 @@ fn run_test( match result { Err(e) => return Err(TestFailure::ExecutionError(e)), Ok(out) => { - if lang_string.should_panic && out.status.success() { + if langstr.should_panic && out.status.success() { return Err(TestFailure::UnexpectedRunPass); - } else if !lang_string.should_panic && !out.status.success() { + } else if !langstr.should_panic && !out.status.success() { return Err(TestFailure::ExecutionFailure(out)); } } @@ -568,389 +573,14 @@ fn make_maybe_absolute_path(path: PathBuf) -> PathBuf { std::env::current_dir().map(|c| c.join(&path)).unwrap_or_else(|_| path) } } - -/// Transforms a test into code that can be compiled into a Rust binary, and returns the number of -/// lines before the test code begins as well as if the output stream supports colors or not. -pub(crate) fn make_test( - s: &str, - crate_name: Option<&str>, - dont_insert_main: bool, - opts: &GlobalTestOptions, - edition: Edition, - test_id: Option<&str>, -) -> (String, usize, bool) { - let (crate_attrs, everything_else, crates) = partition_source(s, edition); - let everything_else = everything_else.trim(); - let mut line_offset = 0; - let mut prog = String::new(); - let mut supports_color = false; - - if opts.attrs.is_empty() { - // If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some - // lints that are commonly triggered in doctests. The crate-level test attributes are - // commonly used to make tests fail in case they trigger warnings, so having this there in - // that case may cause some tests to pass when they shouldn't have. - prog.push_str("#![allow(unused)]\n"); - line_offset += 1; - } - - // Next, any attributes that came from the crate root via #![doc(test(attr(...)))]. - for attr in &opts.attrs { - prog.push_str(&format!("#![{attr}]\n")); - line_offset += 1; - } - - // Now push any outer attributes from the example, assuming they - // are intended to be crate attributes. - prog.push_str(&crate_attrs); - prog.push_str(&crates); - - // Uses librustc_ast to parse the doctest and find if there's a main fn and the extern - // crate already is included. - let result = rustc_driver::catch_fatal_errors(|| { - rustc_span::create_session_if_not_set_then(edition, |_| { - use rustc_errors::emitter::{Emitter, HumanEmitter}; - use rustc_errors::DiagCtxt; - use rustc_parse::parser::ForceCollect; - use rustc_span::source_map::FilePathMapping; - - let filename = FileName::anon_source_code(s); - let source = crates + everything_else; - - // Any errors in parsing should also appear when the doctest is compiled for real, so just - // send all the errors that librustc_ast emits directly into a `Sink` instead of stderr. - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let fallback_bundle = rustc_errors::fallback_fluent_bundle( - rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), - false, - ); - supports_color = - HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle.clone()) - .supports_color(); - - let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle); - - // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser - let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); - let psess = ParseSess::with_dcx(dcx, sm); - - let mut found_main = false; - let mut found_extern_crate = crate_name.is_none(); - let mut found_macro = false; - - let mut parser = match maybe_new_parser_from_source_str(&psess, filename, source) { - Ok(p) => p, - Err(errs) => { - errs.into_iter().for_each(|err| err.cancel()); - return (found_main, found_extern_crate, found_macro); - } - }; - - loop { - match parser.parse_item(ForceCollect::No) { - Ok(Some(item)) => { - if !found_main - && let ast::ItemKind::Fn(..) = item.kind - && item.ident.name == sym::main - { - found_main = true; - } - - if !found_extern_crate - && let ast::ItemKind::ExternCrate(original) = item.kind - { - // This code will never be reached if `crate_name` is none because - // `found_extern_crate` is initialized to `true` if it is none. - let crate_name = crate_name.unwrap(); - - match original { - Some(name) => found_extern_crate = name.as_str() == crate_name, - None => found_extern_crate = item.ident.as_str() == crate_name, - } - } - - if !found_macro && let ast::ItemKind::MacCall(..) = item.kind { - found_macro = true; - } - - if found_main && found_extern_crate { - break; - } - } - Ok(None) => break, - Err(e) => { - e.cancel(); - break; - } - } - - // The supplied item is only used for diagnostics, - // which are swallowed here anyway. - parser.maybe_consume_incorrect_semicolon(None); - } - - // Reset errors so that they won't be reported as compiler bugs when dropping the - // dcx. Any errors in the tests will be reported when the test file is compiled, - // Note that we still need to cancel the errors above otherwise `Diag` will panic on - // drop. - psess.dcx.reset_err_count(); - - (found_main, found_extern_crate, found_macro) - }) - }); - let Ok((already_has_main, already_has_extern_crate, found_macro)) = result else { - // If the parser panicked due to a fatal error, pass the test code through unchanged. - // The error will be reported during compilation. - return (s.to_owned(), 0, false); - }; - - // If a doctest's `fn main` is being masked by a wrapper macro, the parsing loop above won't - // see it. In that case, run the old text-based scan to see if they at least have a main - // function written inside a macro invocation. See - // https://github.com/rust-lang/rust/issues/56898 - let already_has_main = if found_macro && !already_has_main { - s.lines() - .map(|line| { - let comment = line.find("//"); - if let Some(comment_begins) = comment { &line[0..comment_begins] } else { line } - }) - .any(|code| code.contains("fn main")) - } else { - already_has_main - }; - - // Don't inject `extern crate std` because it's already injected by the - // compiler. - if !already_has_extern_crate && !opts.no_crate_inject && crate_name != Some("std") { - if let Some(crate_name) = crate_name { - // Don't inject `extern crate` if the crate is never used. - // NOTE: this is terribly inaccurate because it doesn't actually - // parse the source, but only has false positives, not false - // negatives. - if s.contains(crate_name) { - // rustdoc implicitly inserts an `extern crate` item for the own crate - // which may be unused, so we need to allow the lint. - prog.push_str("#[allow(unused_extern_crates)]\n"); - - prog.push_str(&format!("extern crate r#{crate_name};\n")); - line_offset += 1; - } - } - } - - // FIXME: This code cannot yet handle no_std test cases yet - if dont_insert_main || already_has_main || prog.contains("![no_std]") { - prog.push_str(everything_else); - } else { - let returns_result = everything_else.trim_end().ends_with("(())"); - // Give each doctest main function a unique name. - // This is for example needed for the tooling around `-C instrument-coverage`. - let inner_fn_name = if let Some(test_id) = test_id { - format!("_doctest_main_{test_id}") - } else { - "_inner".into() - }; - let inner_attr = if test_id.is_some() { "#[allow(non_snake_case)] " } else { "" }; - let (main_pre, main_post) = if returns_result { - ( - format!( - "fn main() {{ {inner_attr}fn {inner_fn_name}() -> Result<(), impl core::fmt::Debug> {{\n", - ), - format!("\n}} {inner_fn_name}().unwrap() }}"), - ) - } else if test_id.is_some() { - ( - format!("fn main() {{ {inner_attr}fn {inner_fn_name}() {{\n",), - format!("\n}} {inner_fn_name}() }}"), - ) - } else { - ("fn main() {\n".into(), "\n}".into()) - }; - // Note on newlines: We insert a line/newline *before*, and *after* - // the doctest and adjust the `line_offset` accordingly. - // In the case of `-C instrument-coverage`, this means that the generated - // inner `main` function spans from the doctest opening codeblock to the - // closing one. For example - // /// ``` <- start of the inner main - // /// <- code under doctest - // /// ``` <- end of the inner main - line_offset += 1; - - // add extra 4 spaces for each line to offset the code block - let content = if opts.insert_indent_space { - everything_else - .lines() - .map(|line| format!(" {}", line)) - .collect::<Vec<String>>() - .join("\n") - } else { - everything_else.to_string() - }; - prog.extend([&main_pre, content.as_str(), &main_post].iter().cloned()); - } - - debug!("final doctest:\n{prog}"); - - (prog, line_offset, supports_color) -} - -fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool { - if source.is_empty() { - // Empty content so nothing to check in here... - return true; - } - rustc_driver::catch_fatal_errors(|| { - rustc_span::create_session_if_not_set_then(edition, |_| { - use rustc_errors::emitter::HumanEmitter; - use rustc_errors::DiagCtxt; - use rustc_span::source_map::FilePathMapping; - - let filename = FileName::anon_source_code(source); - // Any errors in parsing should also appear when the doctest is compiled for real, so just - // send all the errors that librustc_ast emits directly into a `Sink` instead of stderr. - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let fallback_bundle = rustc_errors::fallback_fluent_bundle( - rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), - false, - ); - - let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle); - - let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); - let psess = ParseSess::with_dcx(dcx, sm); - let mut parser = - match maybe_new_parser_from_source_str(&psess, filename, source.to_owned()) { - Ok(p) => p, - Err(errs) => { - errs.into_iter().for_each(|err| err.cancel()); - // If there is an unclosed delimiter, an error will be returned by the - // tokentrees. - return false; - } - }; - // If a parsing error happened, it's very likely that the attribute is incomplete. - if let Err(e) = parser.parse_attribute(InnerAttrPolicy::Permitted) { - e.cancel(); - return false; - } - true - }) - }) - .unwrap_or(false) -} - -fn partition_source(s: &str, edition: Edition) -> (String, String, String) { - #[derive(Copy, Clone, PartialEq)] - enum PartitionState { - Attrs, - Crates, - Other, - } - let mut state = PartitionState::Attrs; - let mut before = String::new(); - let mut crates = String::new(); - let mut after = String::new(); - - let mut mod_attr_pending = String::new(); - - for line in s.lines() { - let trimline = line.trim(); - - // FIXME(misdreavus): if a doc comment is placed on an extern crate statement, it will be - // shunted into "everything else" - match state { - PartitionState::Attrs => { - state = if trimline.starts_with("#![") { - if !check_if_attr_is_complete(line, edition) { - mod_attr_pending = line.to_owned(); - } else { - mod_attr_pending.clear(); - } - PartitionState::Attrs - } else if trimline.chars().all(|c| c.is_whitespace()) - || (trimline.starts_with("//") && !trimline.starts_with("///")) - { - PartitionState::Attrs - } else if trimline.starts_with("extern crate") - || trimline.starts_with("#[macro_use] extern crate") - { - PartitionState::Crates - } else { - // First we check if the previous attribute was "complete"... - if !mod_attr_pending.is_empty() { - // If not, then we append the new line into the pending attribute to check - // if this time it's complete... - mod_attr_pending.push_str(line); - if !trimline.is_empty() - && check_if_attr_is_complete(&mod_attr_pending, edition) - { - // If it's complete, then we can clear the pending content. - mod_attr_pending.clear(); - } - // In any case, this is considered as `PartitionState::Attrs` so it's - // prepended before rustdoc's inserts. - PartitionState::Attrs - } else { - PartitionState::Other - } - }; - } - PartitionState::Crates => { - state = if trimline.starts_with("extern crate") - || trimline.starts_with("#[macro_use] extern crate") - || trimline.chars().all(|c| c.is_whitespace()) - || (trimline.starts_with("//") && !trimline.starts_with("///")) - { - PartitionState::Crates - } else { - PartitionState::Other - }; - } - PartitionState::Other => {} - } - - match state { - PartitionState::Attrs => { - before.push_str(line); - before.push('\n'); - } - PartitionState::Crates => { - crates.push_str(line); - crates.push('\n'); - } - PartitionState::Other => { - after.push_str(line); - after.push('\n'); - } - } - } - - debug!("before:\n{before}"); - debug!("crates:\n{crates}"); - debug!("after:\n{after}"); - - (before, after, crates) -} - -pub(crate) struct IndividualTestOptions { - test_builder: Option<PathBuf>, - test_builder_wrappers: Vec<PathBuf>, - is_json_unused_externs_enabled: bool, - should_persist_doctests: bool, - error_format: ErrorOutputType, - test_run_directory: Option<PathBuf>, - nocapture: bool, - arg_file: PathBuf, +struct IndividualTestOptions { outdir: DirState, - runtool: Option<String>, - runtool_args: Vec<String>, - target: TargetTriple, test_id: String, - maybe_sysroot: Option<PathBuf>, + path: PathBuf, } impl IndividualTestOptions { - fn new(options: &RustdocOptions, arg_file: &Path, test_id: String) -> Self { + fn new(options: &RustdocOptions, test_id: String, test_path: PathBuf) -> Self { let outdir = if let Some(ref path) = options.persist_doctests { let mut path = path.clone(); path.push(&test_id); @@ -965,148 +595,75 @@ impl IndividualTestOptions { DirState::Temp(get_doctest_dir().expect("rustdoc needs a tempdir")) }; - Self { - test_builder: options.test_builder.clone(), - test_builder_wrappers: options.test_builder_wrappers.clone(), - is_json_unused_externs_enabled: options.json_unused_externs.is_enabled(), - should_persist_doctests: options.persist_doctests.is_none(), - error_format: options.error_format, - test_run_directory: options.test_run_directory.clone(), - nocapture: options.nocapture, - arg_file: arg_file.into(), - outdir, - runtool: options.runtool.clone(), - runtool_args: options.runtool_args.clone(), - target: options.target.clone(), - test_id, - maybe_sysroot: options.maybe_sysroot.clone(), - } + Self { outdir, test_id, path: test_path } } } -pub(crate) trait Tester { - fn add_test(&mut self, test: String, config: LangString, line: usize); - fn get_line(&self) -> usize { - 0 +/// A doctest scraped from the code, ready to be turned into a runnable test. +struct ScrapedDoctest { + filename: FileName, + line: usize, + logical_path: Vec<String>, + langstr: LangString, + text: String, +} + +impl ScrapedDoctest { + fn edition(&self, opts: &RustdocOptions) -> Edition { + self.langstr.edition.unwrap_or(opts.edition) + } + + fn no_run(&self, opts: &RustdocOptions) -> bool { + self.langstr.no_run || opts.no_run } - fn register_header(&mut self, _name: &str, _level: u32) {} } -pub(crate) struct Collector { - pub(crate) tests: Vec<test::TestDescAndFn>, - - // The name of the test displayed to the user, separated by `::`. - // - // In tests from Rust source, this is the path to the item - // e.g., `["std", "vec", "Vec", "push"]`. - // - // In tests from a markdown file, this is the titles of all headers (h1~h6) - // of the sections that contain the code block, e.g., if the markdown file is - // written as: - // - // ``````markdown - // # Title - // - // ## Subtitle - // - // ```rust - // assert!(true); - // ``` - // `````` - // - // the `names` vector of that test will be `["Title", "Subtitle"]`. - names: Vec<String>, - - rustdoc_options: RustdocOptions, - use_headers: bool, - enable_per_target_ignores: bool, - crate_name: String, +pub(crate) trait DoctestVisitor { + fn visit_test(&mut self, test: String, config: LangString, rel_line: MdRelLine); + fn visit_header(&mut self, _name: &str, _level: u32) {} +} + +struct CreateRunnableDoctests { + tests: Vec<test::TestDescAndFn>, + + rustdoc_options: Arc<RustdocOptions>, opts: GlobalTestOptions, - position: Span, - source_map: Option<Lrc<SourceMap>>, - filename: Option<PathBuf>, visited_tests: FxHashMap<(String, usize), usize>, unused_extern_reports: Arc<Mutex<Vec<UnusedExterns>>>, compiling_test_count: AtomicUsize, - arg_file: PathBuf, } -impl Collector { - pub(crate) fn new( - crate_name: String, - rustdoc_options: RustdocOptions, - use_headers: bool, - opts: GlobalTestOptions, - source_map: Option<Lrc<SourceMap>>, - filename: Option<PathBuf>, - enable_per_target_ignores: bool, - arg_file: PathBuf, - ) -> Collector { - Collector { +impl CreateRunnableDoctests { + fn new(rustdoc_options: RustdocOptions, opts: GlobalTestOptions) -> CreateRunnableDoctests { + CreateRunnableDoctests { tests: Vec::new(), - names: Vec::new(), - rustdoc_options, - use_headers, - enable_per_target_ignores, - crate_name, + rustdoc_options: Arc::new(rustdoc_options), opts, - position: DUMMY_SP, - source_map, - filename, visited_tests: FxHashMap::default(), unused_extern_reports: Default::default(), compiling_test_count: AtomicUsize::new(0), - arg_file, } } - fn generate_name(&self, line: usize, filename: &FileName) -> String { - let mut item_path = self.names.join("::"); + fn generate_name(&self, filename: &FileName, line: usize, logical_path: &[String]) -> String { + let mut item_path = logical_path.join("::"); item_path.retain(|c| c != ' '); if !item_path.is_empty() { item_path.push(' '); } - format!("{} - {item_path}(line {line})", filename.prefer_local()) - } - - pub(crate) fn set_position(&mut self, position: Span) { - self.position = position; - } - - fn get_filename(&self) -> FileName { - if let Some(ref source_map) = self.source_map { - let filename = source_map.span_to_filename(self.position); - if let FileName::Real(ref filename) = filename - && let Ok(cur_dir) = env::current_dir() - && let Some(local_path) = filename.local_path() - && let Ok(path) = local_path.strip_prefix(&cur_dir) - { - return path.to_owned().into(); - } - filename - } else if let Some(ref filename) = self.filename { - filename.clone().into() - } else { - FileName::Custom("input".to_owned()) - } + format!("{} - {item_path}(line {line})", filename.prefer_remapped_unconditionaly()) } -} -impl Tester for Collector { - fn add_test(&mut self, test: String, config: LangString, line: usize) { - let filename = self.get_filename(); - let name = self.generate_name(line, &filename); - let crate_name = self.crate_name.clone(); + fn add_test(&mut self, test: ScrapedDoctest) { + let name = self.generate_name(&test.filename, test.line, &test.logical_path); let opts = self.opts.clone(); - let edition = config.edition.unwrap_or(self.rustdoc_options.edition); let target_str = self.rustdoc_options.target.to_string(); let unused_externs = self.unused_extern_reports.clone(); - let no_run = config.no_run || self.rustdoc_options.no_run; - if !config.compile_fail { + if !test.langstr.compile_fail { self.compiling_test_count.fetch_add(1, Ordering::SeqCst); } - let path = match &filename { + let path = match &test.filename { FileName::Real(path) => { if let Some(local_path) = path.local_path() { local_path.to_path_buf() @@ -1119,7 +676,8 @@ impl Tester for Collector { }; // For example `module/file.rs` would become `module_file_rs` - let file = filename + let file = test + .filename .prefer_local() .to_string_lossy() .chars() @@ -1128,22 +686,25 @@ impl Tester for Collector { let test_id = format!( "{file}_{line}_{number}", file = file, - line = line, + line = test.line, number = { // Increases the current test number, if this file already // exists or it creates a new entry with a test number of 0. - self.visited_tests.entry((file.clone(), line)).and_modify(|v| *v += 1).or_insert(0) + self.visited_tests + .entry((file.clone(), test.line)) + .and_modify(|v| *v += 1) + .or_insert(0) }, ); - let rustdoc_test_options = - IndividualTestOptions::new(&self.rustdoc_options, &self.arg_file, test_id); + let rustdoc_options = self.rustdoc_options.clone(); + let rustdoc_test_options = IndividualTestOptions::new(&self.rustdoc_options, test_id, path); - debug!("creating test {name}: {test}"); + debug!("creating test {name}: {}", test.text); self.tests.push(test::TestDescAndFn { desc: test::TestDesc { name: test::DynTestName(name), - ignore: match config.ignore { + ignore: match test.langstr.ignore { Ignore::All => true, Ignore::None => false, Ignore::Some(ref ignores) => ignores.iter().any(|s| target_str.contains(s)), @@ -1156,252 +717,103 @@ impl Tester for Collector { end_col: 0, // compiler failures are test failures should_panic: test::ShouldPanic::No, - compile_fail: config.compile_fail, - no_run, + compile_fail: test.langstr.compile_fail, + no_run: test.no_run(&rustdoc_options), test_type: test::TestType::DocTest, }, testfn: test::DynTestFn(Box::new(move || { - let report_unused_externs = |uext| { - unused_externs.lock().unwrap().push(uext); - }; - let res = run_test( - &test, - &crate_name, - line, - rustdoc_test_options, - config, - no_run, - &opts, - edition, - path, - report_unused_externs, - ); - - if let Err(err) = res { - match err { - TestFailure::CompileError => { - eprint!("Couldn't compile the test."); - } - TestFailure::UnexpectedCompilePass => { - eprint!("Test compiled successfully, but it's marked `compile_fail`."); - } - TestFailure::UnexpectedRunPass => { - eprint!("Test executable succeeded, but it's marked `should_panic`."); - } - TestFailure::MissingErrorCodes(codes) => { - eprint!("Some expected error codes were not found: {codes:?}"); - } - TestFailure::ExecutionError(err) => { - eprint!("Couldn't run the test: {err}"); - if err.kind() == io::ErrorKind::PermissionDenied { - eprint!(" - maybe your tempdir is mounted with noexec?"); - } - } - TestFailure::ExecutionFailure(out) => { - eprintln!("Test executable failed ({reason}).", reason = out.status); - - // FIXME(#12309): An unfortunate side-effect of capturing the test - // executable's output is that the relative ordering between the test's - // stdout and stderr is lost. However, this is better than the - // alternative: if the test executable inherited the parent's I/O - // handles the output wouldn't be captured at all, even on success. - // - // The ordering could be preserved if the test process' stderr was - // redirected to stdout, but that functionality does not exist in the - // standard library, so it may not be portable enough. - let stdout = str::from_utf8(&out.stdout).unwrap_or_default(); - let stderr = str::from_utf8(&out.stderr).unwrap_or_default(); - - if !stdout.is_empty() || !stderr.is_empty() { - eprintln!(); - - if !stdout.is_empty() { - eprintln!("stdout:\n{stdout}"); - } - - if !stderr.is_empty() { - eprintln!("stderr:\n{stderr}"); - } - } - } - } - - panic::resume_unwind(Box::new(())); - } - Ok(()) + doctest_run_fn(rustdoc_test_options, opts, test, rustdoc_options, unused_externs) })), }); } +} - fn get_line(&self) -> usize { - if let Some(ref source_map) = self.source_map { - let line = self.position.lo().to_usize(); - let line = source_map.lookup_char_pos(BytePos(line as u32)).line; - if line > 0 { line - 1 } else { line } - } else { - 0 - } - } +fn doctest_run_fn( + test_opts: IndividualTestOptions, + global_opts: GlobalTestOptions, + scraped_test: ScrapedDoctest, + rustdoc_options: Arc<RustdocOptions>, + unused_externs: Arc<Mutex<Vec<UnusedExterns>>>, +) -> Result<(), String> { + let report_unused_externs = |uext| { + unused_externs.lock().unwrap().push(uext); + }; + let edition = scraped_test.edition(&rustdoc_options); + let (full_test_code, full_test_line_offset, supports_color) = make_test( + &scraped_test.text, + Some(&global_opts.crate_name), + scraped_test.langstr.test_harness, + &global_opts, + edition, + Some(&test_opts.test_id), + ); + let runnable_test = RunnableDoctest { + full_test_code, + full_test_line_offset, + test_opts, + global_opts, + scraped_test, + }; + let res = run_test(runnable_test, &rustdoc_options, supports_color, report_unused_externs); - fn register_header(&mut self, name: &str, level: u32) { - if self.use_headers { - // We use these headings as test names, so it's good if - // they're valid identifiers. - let name = name - .chars() - .enumerate() - .map(|(i, c)| { - if (i == 0 && rustc_lexer::is_id_start(c)) - || (i != 0 && rustc_lexer::is_id_continue(c)) - { - c - } else { - '_' - } - }) - .collect::<String>(); - - // Here we try to efficiently assemble the header titles into the - // test name in the form of `h1::h2::h3::h4::h5::h6`. - // - // Suppose that originally `self.names` contains `[h1, h2, h3]`... - let level = level as usize; - if level <= self.names.len() { - // ... Consider `level == 2`. All headers in the lower levels - // are irrelevant in this new level. So we should reset - // `self.names` to contain headers until <h2>, and replace that - // slot with the new name: `[h1, name]`. - self.names.truncate(level); - self.names[level - 1] = name; - } else { - // ... On the other hand, consider `level == 5`. This means we - // need to extend `self.names` to contain five headers. We fill - // in the missing level (<h4>) with `_`. Thus `self.names` will - // become `[h1, h2, h3, "_", name]`. - if level - 1 > self.names.len() { - self.names.resize(level - 1, "_".to_owned()); + if let Err(err) = res { + match err { + TestFailure::CompileError => { + eprint!("Couldn't compile the test."); + } + TestFailure::UnexpectedCompilePass => { + eprint!("Test compiled successfully, but it's marked `compile_fail`."); + } + TestFailure::UnexpectedRunPass => { + eprint!("Test executable succeeded, but it's marked `should_panic`."); + } + TestFailure::MissingErrorCodes(codes) => { + eprint!("Some expected error codes were not found: {codes:?}"); + } + TestFailure::ExecutionError(err) => { + eprint!("Couldn't run the test: {err}"); + if err.kind() == io::ErrorKind::PermissionDenied { + eprint!(" - maybe your tempdir is mounted with noexec?"); } - self.names.push(name); } - } - } -} - -#[cfg(test)] // used in tests -impl Tester for Vec<usize> { - fn add_test(&mut self, _test: String, _config: LangString, line: usize) { - self.push(line); - } -} - -struct HirCollector<'a, 'hir, 'tcx> { - sess: &'a Session, - collector: &'a mut Collector, - map: Map<'hir>, - codes: ErrorCodes, - tcx: TyCtxt<'tcx>, -} + TestFailure::ExecutionFailure(out) => { + eprintln!("Test executable failed ({reason}).", reason = out.status); + + // FIXME(#12309): An unfortunate side-effect of capturing the test + // executable's output is that the relative ordering between the test's + // stdout and stderr is lost. However, this is better than the + // alternative: if the test executable inherited the parent's I/O + // handles the output wouldn't be captured at all, even on success. + // + // The ordering could be preserved if the test process' stderr was + // redirected to stdout, but that functionality does not exist in the + // standard library, so it may not be portable enough. + let stdout = str::from_utf8(&out.stdout).unwrap_or_default(); + let stderr = str::from_utf8(&out.stderr).unwrap_or_default(); + + if !stdout.is_empty() || !stderr.is_empty() { + eprintln!(); + + if !stdout.is_empty() { + eprintln!("stdout:\n{stdout}"); + } -impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { - fn visit_testable<F: FnOnce(&mut Self)>( - &mut self, - name: String, - def_id: LocalDefId, - sp: Span, - nested: F, - ) { - let ast_attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id)); - if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) { - if !cfg.matches(&self.sess.psess, Some(self.tcx.features())) { - return; + if !stderr.is_empty() { + eprintln!("stderr:\n{stderr}"); + } + } } } - let has_name = !name.is_empty(); - if has_name { - self.collector.names.push(name); - } - - // The collapse-docs pass won't combine sugared/raw doc attributes, or included files with - // anything else, this will combine them for us. - let attrs = Attributes::from_ast(ast_attrs); - if let Some(doc) = attrs.opt_doc_value() { - // Use the outermost invocation, so that doctest names come from where the docs were written. - let span = ast_attrs - .iter() - .find(|attr| attr.doc_str().is_some()) - .map(|attr| attr.span.ctxt().outer_expn().expansion_cause().unwrap_or(attr.span)) - .unwrap_or(DUMMY_SP); - self.collector.set_position(span); - markdown::find_testable_code( - &doc, - self.collector, - self.codes, - self.collector.enable_per_target_ignores, - Some(&crate::html::markdown::ExtraInfo::new( - self.tcx, - def_id.to_def_id(), - span_of_fragments(&attrs.doc_strings).unwrap_or(sp), - )), - ); - } - - nested(self); - - if has_name { - self.collector.names.pop(); - } + panic::resume_unwind(Box::new(())); } + Ok(()) } -impl<'a, 'hir, 'tcx> intravisit::Visitor<'hir> for HirCollector<'a, 'hir, 'tcx> { - type NestedFilter = nested_filter::All; - - fn nested_visit_map(&mut self) -> Self::Map { - self.map - } - - fn visit_item(&mut self, item: &'hir hir::Item<'_>) { - let name = match &item.kind { - hir::ItemKind::Impl(impl_) => { - rustc_hir_pretty::id_to_string(&self.map, impl_.self_ty.hir_id) - } - _ => item.ident.to_string(), - }; - - self.visit_testable(name, item.owner_id.def_id, item.span, |this| { - intravisit::walk_item(this, item); - }); - } - - fn visit_trait_item(&mut self, item: &'hir hir::TraitItem<'_>) { - self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| { - intravisit::walk_trait_item(this, item); - }); - } - - fn visit_impl_item(&mut self, item: &'hir hir::ImplItem<'_>) { - self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| { - intravisit::walk_impl_item(this, item); - }); - } - - fn visit_foreign_item(&mut self, item: &'hir hir::ForeignItem<'_>) { - self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| { - intravisit::walk_foreign_item(this, item); - }); - } - - fn visit_variant(&mut self, v: &'hir hir::Variant<'_>) { - self.visit_testable(v.ident.to_string(), v.def_id, v.span, |this| { - intravisit::walk_variant(this, v); - }); - } - - fn visit_field_def(&mut self, f: &'hir hir::FieldDef<'_>) { - self.visit_testable(f.ident.to_string(), f.def_id, f.span, |this| { - intravisit::walk_field_def(this, f); - }); +#[cfg(test)] // used in tests +impl DoctestVisitor for Vec<usize> { + fn visit_test(&mut self, _test: String, _config: LangString, rel_line: MdRelLine) { + self.push(1 + rel_line.offset()); } } diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs new file mode 100644 index 00000000000..599611407ed --- /dev/null +++ b/src/librustdoc/doctest/make.rs @@ -0,0 +1,393 @@ +//! Logic for transforming the raw code given by the user into something actually +//! runnable, e.g. by adding a `main` function if it doesn't already exist. + +use std::io; + +use rustc_ast as ast; +use rustc_data_structures::sync::Lrc; +use rustc_errors::emitter::stderr_destination; +use rustc_errors::{ColorConfig, FatalError}; +use rustc_parse::new_parser_from_source_str; +use rustc_parse::parser::attr::InnerAttrPolicy; +use rustc_session::parse::ParseSess; +use rustc_span::edition::Edition; +use rustc_span::source_map::SourceMap; +use rustc_span::symbol::sym; +use rustc_span::FileName; + +use super::GlobalTestOptions; + +/// Transforms a test into code that can be compiled into a Rust binary, and returns the number of +/// lines before the test code begins as well as if the output stream supports colors or not. +pub(crate) fn make_test( + s: &str, + crate_name: Option<&str>, + dont_insert_main: bool, + opts: &GlobalTestOptions, + edition: Edition, + test_id: Option<&str>, +) -> (String, usize, bool) { + let (crate_attrs, everything_else, crates) = partition_source(s, edition); + let everything_else = everything_else.trim(); + let mut line_offset = 0; + let mut prog = String::new(); + let mut supports_color = false; + + if opts.attrs.is_empty() { + // If there aren't any attributes supplied by #![doc(test(attr(...)))], then allow some + // lints that are commonly triggered in doctests. The crate-level test attributes are + // commonly used to make tests fail in case they trigger warnings, so having this there in + // that case may cause some tests to pass when they shouldn't have. + prog.push_str("#![allow(unused)]\n"); + line_offset += 1; + } + + // Next, any attributes that came from the crate root via #![doc(test(attr(...)))]. + for attr in &opts.attrs { + prog.push_str(&format!("#![{attr}]\n")); + line_offset += 1; + } + + // Now push any outer attributes from the example, assuming they + // are intended to be crate attributes. + prog.push_str(&crate_attrs); + prog.push_str(&crates); + + // Uses librustc_ast to parse the doctest and find if there's a main fn and the extern + // crate already is included. + let Ok((already_has_main, already_has_extern_crate)) = + check_for_main_and_extern_crate(crate_name, s.to_owned(), edition, &mut supports_color) + else { + // If the parser panicked due to a fatal error, pass the test code through unchanged. + // The error will be reported during compilation. + return (s.to_owned(), 0, false); + }; + + // Don't inject `extern crate std` because it's already injected by the + // compiler. + if !already_has_extern_crate && !opts.no_crate_inject && crate_name != Some("std") { + if let Some(crate_name) = crate_name { + // Don't inject `extern crate` if the crate is never used. + // NOTE: this is terribly inaccurate because it doesn't actually + // parse the source, but only has false positives, not false + // negatives. + if s.contains(crate_name) { + // rustdoc implicitly inserts an `extern crate` item for the own crate + // which may be unused, so we need to allow the lint. + prog.push_str("#[allow(unused_extern_crates)]\n"); + + prog.push_str(&format!("extern crate r#{crate_name};\n")); + line_offset += 1; + } + } + } + + // FIXME: This code cannot yet handle no_std test cases yet + if dont_insert_main || already_has_main || prog.contains("![no_std]") { + prog.push_str(everything_else); + } else { + let returns_result = everything_else.trim_end().ends_with("(())"); + // Give each doctest main function a unique name. + // This is for example needed for the tooling around `-C instrument-coverage`. + let inner_fn_name = if let Some(test_id) = test_id { + format!("_doctest_main_{test_id}") + } else { + "_inner".into() + }; + let inner_attr = if test_id.is_some() { "#[allow(non_snake_case)] " } else { "" }; + let (main_pre, main_post) = if returns_result { + ( + format!( + "fn main() {{ {inner_attr}fn {inner_fn_name}() -> Result<(), impl core::fmt::Debug> {{\n", + ), + format!("\n}} {inner_fn_name}().unwrap() }}"), + ) + } else if test_id.is_some() { + ( + format!("fn main() {{ {inner_attr}fn {inner_fn_name}() {{\n",), + format!("\n}} {inner_fn_name}() }}"), + ) + } else { + ("fn main() {\n".into(), "\n}".into()) + }; + // Note on newlines: We insert a line/newline *before*, and *after* + // the doctest and adjust the `line_offset` accordingly. + // In the case of `-C instrument-coverage`, this means that the generated + // inner `main` function spans from the doctest opening codeblock to the + // closing one. For example + // /// ``` <- start of the inner main + // /// <- code under doctest + // /// ``` <- end of the inner main + line_offset += 1; + + // add extra 4 spaces for each line to offset the code block + let content = if opts.insert_indent_space { + everything_else + .lines() + .map(|line| format!(" {}", line)) + .collect::<Vec<String>>() + .join("\n") + } else { + everything_else.to_string() + }; + prog.extend([&main_pre, content.as_str(), &main_post].iter().cloned()); + } + + debug!("final doctest:\n{prog}"); + + (prog, line_offset, supports_color) +} + +fn check_for_main_and_extern_crate( + crate_name: Option<&str>, + source: String, + edition: Edition, + supports_color: &mut bool, +) -> Result<(bool, bool), FatalError> { + let result = rustc_driver::catch_fatal_errors(|| { + rustc_span::create_session_if_not_set_then(edition, |_| { + use rustc_errors::emitter::{Emitter, HumanEmitter}; + use rustc_errors::DiagCtxt; + use rustc_parse::parser::ForceCollect; + use rustc_span::source_map::FilePathMapping; + + let filename = FileName::anon_source_code(&source); + + // Any errors in parsing should also appear when the doctest is compiled for real, so just + // send all the errors that librustc_ast emits directly into a `Sink` instead of stderr. + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let fallback_bundle = rustc_errors::fallback_fluent_bundle( + rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), + false, + ); + *supports_color = + HumanEmitter::new(stderr_destination(ColorConfig::Auto), fallback_bundle.clone()) + .supports_color(); + + let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle); + + // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser + let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); + let psess = ParseSess::with_dcx(dcx, sm); + + let mut found_main = false; + let mut found_extern_crate = crate_name.is_none(); + let mut found_macro = false; + + let mut parser = match new_parser_from_source_str(&psess, filename, source.clone()) { + Ok(p) => p, + Err(errs) => { + errs.into_iter().for_each(|err| err.cancel()); + return (found_main, found_extern_crate, found_macro); + } + }; + + loop { + match parser.parse_item(ForceCollect::No) { + Ok(Some(item)) => { + if !found_main + && let ast::ItemKind::Fn(..) = item.kind + && item.ident.name == sym::main + { + found_main = true; + } + + if !found_extern_crate + && let ast::ItemKind::ExternCrate(original) = item.kind + { + // This code will never be reached if `crate_name` is none because + // `found_extern_crate` is initialized to `true` if it is none. + let crate_name = crate_name.unwrap(); + + match original { + Some(name) => found_extern_crate = name.as_str() == crate_name, + None => found_extern_crate = item.ident.as_str() == crate_name, + } + } + + if !found_macro && let ast::ItemKind::MacCall(..) = item.kind { + found_macro = true; + } + + if found_main && found_extern_crate { + break; + } + } + Ok(None) => break, + Err(e) => { + e.cancel(); + break; + } + } + + // The supplied item is only used for diagnostics, + // which are swallowed here anyway. + parser.maybe_consume_incorrect_semicolon(None); + } + + // Reset errors so that they won't be reported as compiler bugs when dropping the + // dcx. Any errors in the tests will be reported when the test file is compiled, + // Note that we still need to cancel the errors above otherwise `Diag` will panic on + // drop. + psess.dcx.reset_err_count(); + + (found_main, found_extern_crate, found_macro) + }) + }); + let (already_has_main, already_has_extern_crate, found_macro) = result?; + + // If a doctest's `fn main` is being masked by a wrapper macro, the parsing loop above won't + // see it. In that case, run the old text-based scan to see if they at least have a main + // function written inside a macro invocation. See + // https://github.com/rust-lang/rust/issues/56898 + let already_has_main = if found_macro && !already_has_main { + source + .lines() + .map(|line| { + let comment = line.find("//"); + if let Some(comment_begins) = comment { &line[0..comment_begins] } else { line } + }) + .any(|code| code.contains("fn main")) + } else { + already_has_main + }; + + Ok((already_has_main, already_has_extern_crate)) +} + +fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool { + if source.is_empty() { + // Empty content so nothing to check in here... + return true; + } + rustc_driver::catch_fatal_errors(|| { + rustc_span::create_session_if_not_set_then(edition, |_| { + use rustc_errors::emitter::HumanEmitter; + use rustc_errors::DiagCtxt; + use rustc_span::source_map::FilePathMapping; + + let filename = FileName::anon_source_code(source); + // Any errors in parsing should also appear when the doctest is compiled for real, so just + // send all the errors that librustc_ast emits directly into a `Sink` instead of stderr. + let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let fallback_bundle = rustc_errors::fallback_fluent_bundle( + rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), + false, + ); + + let emitter = HumanEmitter::new(Box::new(io::sink()), fallback_bundle); + + let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); + let psess = ParseSess::with_dcx(dcx, sm); + let mut parser = match new_parser_from_source_str(&psess, filename, source.to_owned()) { + Ok(p) => p, + Err(errs) => { + errs.into_iter().for_each(|err| err.cancel()); + // If there is an unclosed delimiter, an error will be returned by the + // tokentrees. + return false; + } + }; + // If a parsing error happened, it's very likely that the attribute is incomplete. + if let Err(e) = parser.parse_attribute(InnerAttrPolicy::Permitted) { + e.cancel(); + return false; + } + true + }) + }) + .unwrap_or(false) +} + +fn partition_source(s: &str, edition: Edition) -> (String, String, String) { + #[derive(Copy, Clone, PartialEq)] + enum PartitionState { + Attrs, + Crates, + Other, + } + let mut state = PartitionState::Attrs; + let mut before = String::new(); + let mut crates = String::new(); + let mut after = String::new(); + + let mut mod_attr_pending = String::new(); + + for line in s.lines() { + let trimline = line.trim(); + + // FIXME(misdreavus): if a doc comment is placed on an extern crate statement, it will be + // shunted into "everything else" + match state { + PartitionState::Attrs => { + state = if trimline.starts_with("#![") { + if !check_if_attr_is_complete(line, edition) { + mod_attr_pending = line.to_owned(); + } else { + mod_attr_pending.clear(); + } + PartitionState::Attrs + } else if trimline.chars().all(|c| c.is_whitespace()) + || (trimline.starts_with("//") && !trimline.starts_with("///")) + { + PartitionState::Attrs + } else if trimline.starts_with("extern crate") + || trimline.starts_with("#[macro_use] extern crate") + { + PartitionState::Crates + } else { + // First we check if the previous attribute was "complete"... + if !mod_attr_pending.is_empty() { + // If not, then we append the new line into the pending attribute to check + // if this time it's complete... + mod_attr_pending.push_str(line); + if !trimline.is_empty() + && check_if_attr_is_complete(&mod_attr_pending, edition) + { + // If it's complete, then we can clear the pending content. + mod_attr_pending.clear(); + } + // In any case, this is considered as `PartitionState::Attrs` so it's + // prepended before rustdoc's inserts. + PartitionState::Attrs + } else { + PartitionState::Other + } + }; + } + PartitionState::Crates => { + state = if trimline.starts_with("extern crate") + || trimline.starts_with("#[macro_use] extern crate") + || trimline.chars().all(|c| c.is_whitespace()) + || (trimline.starts_with("//") && !trimline.starts_with("///")) + { + PartitionState::Crates + } else { + PartitionState::Other + }; + } + PartitionState::Other => {} + } + + match state { + PartitionState::Attrs => { + before.push_str(line); + before.push('\n'); + } + PartitionState::Crates => { + crates.push_str(line); + crates.push('\n'); + } + PartitionState::Other => { + after.push_str(line); + after.push('\n'); + } + } + } + + debug!("before:\n{before}"); + debug!("crates:\n{crates}"); + debug!("after:\n{after}"); + + (before, after, crates) +} diff --git a/src/librustdoc/doctest/markdown.rs b/src/librustdoc/doctest/markdown.rs new file mode 100644 index 00000000000..b8ab7adb36e --- /dev/null +++ b/src/librustdoc/doctest/markdown.rs @@ -0,0 +1,125 @@ +//! Doctest functionality used only for doctests in `.md` Markdown files. + +use std::fs::read_to_string; + +use rustc_span::FileName; +use tempfile::tempdir; + +use super::{ + generate_args_file, CreateRunnableDoctests, DoctestVisitor, GlobalTestOptions, ScrapedDoctest, +}; +use crate::config::Options; +use crate::html::markdown::{find_testable_code, ErrorCodes, LangString, MdRelLine}; + +struct MdCollector { + tests: Vec<ScrapedDoctest>, + cur_path: Vec<String>, + filename: FileName, +} + +impl DoctestVisitor for MdCollector { + fn visit_test(&mut self, test: String, config: LangString, rel_line: MdRelLine) { + let filename = self.filename.clone(); + // First line of Markdown is line 1. + let line = 1 + rel_line.offset(); + self.tests.push(ScrapedDoctest { + filename, + line, + logical_path: self.cur_path.clone(), + langstr: config, + text: test, + }); + } + + fn visit_header(&mut self, name: &str, level: u32) { + // We use these headings as test names, so it's good if + // they're valid identifiers. + let name = name + .chars() + .enumerate() + .map(|(i, c)| { + if (i == 0 && rustc_lexer::is_id_start(c)) + || (i != 0 && rustc_lexer::is_id_continue(c)) + { + c + } else { + '_' + } + }) + .collect::<String>(); + + // Here we try to efficiently assemble the header titles into the + // test name in the form of `h1::h2::h3::h4::h5::h6`. + // + // Suppose that originally `self.cur_path` contains `[h1, h2, h3]`... + let level = level as usize; + if level <= self.cur_path.len() { + // ... Consider `level == 2`. All headers in the lower levels + // are irrelevant in this new level. So we should reset + // `self.names` to contain headers until <h2>, and replace that + // slot with the new name: `[h1, name]`. + self.cur_path.truncate(level); + self.cur_path[level - 1] = name; + } else { + // ... On the other hand, consider `level == 5`. This means we + // need to extend `self.names` to contain five headers. We fill + // in the missing level (<h4>) with `_`. Thus `self.names` will + // become `[h1, h2, h3, "_", name]`. + if level - 1 > self.cur_path.len() { + self.cur_path.resize(level - 1, "_".to_owned()); + } + self.cur_path.push(name); + } + } +} + +/// Runs any tests/code examples in the markdown file `options.input`. +pub(crate) fn test(options: Options) -> Result<(), String> { + use rustc_session::config::Input; + let input_str = match &options.input { + Input::File(path) => { + read_to_string(&path).map_err(|err| format!("{}: {err}", path.display()))? + } + Input::Str { name: _, input } => input.clone(), + }; + + // Obviously not a real crate name, but close enough for purposes of doctests. + let crate_name = options.input.filestem().to_string(); + let temp_dir = + tempdir().map_err(|error| format!("failed to create temporary directory: {error:?}"))?; + let args_file = temp_dir.path().join("rustdoc-cfgs"); + generate_args_file(&args_file, &options)?; + + let opts = GlobalTestOptions { + crate_name, + no_crate_inject: true, + insert_indent_space: false, + attrs: vec![], + args_file, + }; + + let mut md_collector = MdCollector { + tests: vec![], + cur_path: vec![], + filename: options + .input + .opt_path() + .map(ToOwned::to_owned) + .map(FileName::from) + .unwrap_or(FileName::Custom("input".to_owned())), + }; + let codes = ErrorCodes::from(options.unstable_features.is_nightly_build()); + + find_testable_code( + &input_str, + &mut md_collector, + codes, + options.enable_per_target_ignores, + None, + ); + + let mut collector = CreateRunnableDoctests::new(options.clone(), opts); + md_collector.tests.into_iter().for_each(|t| collector.add_test(t)); + crate::doctest::run_tests(options.test_args, options.nocapture, collector.tests); + Ok(()) +} diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs new file mode 100644 index 00000000000..fc8e119ccc2 --- /dev/null +++ b/src/librustdoc/doctest/rust.rs @@ -0,0 +1,200 @@ +//! Doctest functionality used only for doctests in `.rs` source files. + +use std::env; + +use rustc_data_structures::{fx::FxHashSet, sync::Lrc}; +use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; +use rustc_hir::{self as hir, intravisit, CRATE_HIR_ID}; +use rustc_middle::hir::map::Map; +use rustc_middle::hir::nested_filter; +use rustc_middle::ty::TyCtxt; +use rustc_resolve::rustdoc::span_of_fragments; +use rustc_session::Session; +use rustc_span::source_map::SourceMap; +use rustc_span::{BytePos, FileName, Pos, Span, DUMMY_SP}; + +use super::{DoctestVisitor, ScrapedDoctest}; +use crate::clean::{types::AttributesExt, Attributes}; +use crate::html::markdown::{self, ErrorCodes, LangString, MdRelLine}; + +struct RustCollector { + source_map: Lrc<SourceMap>, + tests: Vec<ScrapedDoctest>, + cur_path: Vec<String>, + position: Span, +} + +impl RustCollector { + fn get_filename(&self) -> FileName { + let filename = self.source_map.span_to_filename(self.position); + if let FileName::Real(ref filename) = filename { + let path = filename.remapped_path_if_available(); + // Strip the cwd prefix from the path. This will likely exist if + // the path was not remapped. + let path = env::current_dir() + .map(|cur_dir| path.strip_prefix(&cur_dir).unwrap_or(path)) + .unwrap_or(path); + return path.to_owned().into(); + } + filename + } + + fn get_base_line(&self) -> usize { + let sp_lo = self.position.lo().to_usize(); + let loc = self.source_map.lookup_char_pos(BytePos(sp_lo as u32)); + loc.line + } +} + +impl DoctestVisitor for RustCollector { + fn visit_test(&mut self, test: String, config: LangString, rel_line: MdRelLine) { + let line = self.get_base_line() + rel_line.offset(); + self.tests.push(ScrapedDoctest { + filename: self.get_filename(), + line, + logical_path: self.cur_path.clone(), + langstr: config, + text: test, + }); + } + + fn visit_header(&mut self, _name: &str, _level: u32) {} +} + +pub(super) struct HirCollector<'a, 'tcx> { + sess: &'a Session, + map: Map<'tcx>, + codes: ErrorCodes, + tcx: TyCtxt<'tcx>, + enable_per_target_ignores: bool, + collector: RustCollector, +} + +impl<'a, 'tcx> HirCollector<'a, 'tcx> { + pub fn new( + sess: &'a Session, + map: Map<'tcx>, + codes: ErrorCodes, + enable_per_target_ignores: bool, + tcx: TyCtxt<'tcx>, + ) -> Self { + let collector = RustCollector { + source_map: sess.psess.clone_source_map(), + cur_path: vec![], + position: DUMMY_SP, + tests: vec![], + }; + Self { sess, map, codes, enable_per_target_ignores, tcx, collector } + } + + pub fn collect_crate(mut self) -> Vec<ScrapedDoctest> { + let tcx = self.tcx; + self.visit_testable("".to_string(), CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID), |this| { + tcx.hir().walk_toplevel_module(this) + }); + self.collector.tests + } +} + +impl<'a, 'tcx> HirCollector<'a, 'tcx> { + fn visit_testable<F: FnOnce(&mut Self)>( + &mut self, + name: String, + def_id: LocalDefId, + sp: Span, + nested: F, + ) { + let ast_attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id)); + if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) { + if !cfg.matches(&self.sess.psess, Some(self.tcx.features())) { + return; + } + } + + let has_name = !name.is_empty(); + if has_name { + self.collector.cur_path.push(name); + } + + // The collapse-docs pass won't combine sugared/raw doc attributes, or included files with + // anything else, this will combine them for us. + let attrs = Attributes::from_ast(ast_attrs); + if let Some(doc) = attrs.opt_doc_value() { + // Use the outermost invocation, so that doctest names come from where the docs were written. + let span = ast_attrs + .iter() + .find(|attr| attr.doc_str().is_some()) + .map(|attr| attr.span.ctxt().outer_expn().expansion_cause().unwrap_or(attr.span)) + .unwrap_or(DUMMY_SP); + self.collector.position = span; + markdown::find_testable_code( + &doc, + &mut self.collector, + self.codes, + self.enable_per_target_ignores, + Some(&crate::html::markdown::ExtraInfo::new( + self.tcx, + def_id.to_def_id(), + span_of_fragments(&attrs.doc_strings).unwrap_or(sp), + )), + ); + } + + nested(self); + + if has_name { + self.collector.cur_path.pop(); + } + } +} + +impl<'a, 'tcx> intravisit::Visitor<'tcx> for HirCollector<'a, 'tcx> { + type NestedFilter = nested_filter::All; + + fn nested_visit_map(&mut self) -> Self::Map { + self.map + } + + fn visit_item(&mut self, item: &'tcx hir::Item<'_>) { + let name = match &item.kind { + hir::ItemKind::Impl(impl_) => { + rustc_hir_pretty::id_to_string(&self.map, impl_.self_ty.hir_id) + } + _ => item.ident.to_string(), + }; + + self.visit_testable(name, item.owner_id.def_id, item.span, |this| { + intravisit::walk_item(this, item); + }); + } + + fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'_>) { + self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| { + intravisit::walk_trait_item(this, item); + }); + } + + fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'_>) { + self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| { + intravisit::walk_impl_item(this, item); + }); + } + + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'_>) { + self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| { + intravisit::walk_foreign_item(this, item); + }); + } + + fn visit_variant(&mut self, v: &'tcx hir::Variant<'_>) { + self.visit_testable(v.ident.to_string(), v.def_id, v.span, |this| { + intravisit::walk_variant(this, v); + }); + } + + fn visit_field_def(&mut self, f: &'tcx hir::FieldDef<'_>) { + self.visit_testable(f.ident.to_string(), f.def_id, f.span, |this| { + intravisit::walk_field_def(this, f); + }); + } +} diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index 9629acb31eb..9124ec63267 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -1,10 +1,23 @@ +use std::path::PathBuf; + use super::{make_test, GlobalTestOptions}; use rustc_span::edition::DEFAULT_EDITION; +/// Default [`GlobalTestOptions`] for these unit tests. +fn default_global_opts(crate_name: impl Into<String>) -> GlobalTestOptions { + GlobalTestOptions { + crate_name: crate_name.into(), + no_crate_inject: false, + insert_indent_space: false, + attrs: vec![], + args_file: PathBuf::new(), + } +} + #[test] fn make_test_basic() { //basic use: wraps with `fn main`, adds `#![allow(unused)]` - let opts = GlobalTestOptions::default(); + let opts = default_global_opts(""); let input = "assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] fn main() { @@ -19,7 +32,7 @@ assert_eq!(2+2, 4); fn make_test_crate_name_no_use() { // If you give a crate name but *don't* use it within the test, it won't bother inserting // the `extern crate` statement. - let opts = GlobalTestOptions::default(); + let opts = default_global_opts("asdf"); let input = "assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] fn main() { @@ -34,7 +47,7 @@ assert_eq!(2+2, 4); fn make_test_crate_name() { // If you give a crate name and use it within the test, it will insert an `extern crate` // statement before `fn main`. - let opts = GlobalTestOptions::default(); + let opts = default_global_opts("asdf"); let input = "use asdf::qwop; assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] @@ -53,8 +66,7 @@ assert_eq!(2+2, 4); fn make_test_no_crate_inject() { // Even if you do use the crate within the test, setting `opts.no_crate_inject` will skip // adding it anyway. - let opts = - GlobalTestOptions { no_crate_inject: true, attrs: vec![], insert_indent_space: false }; + let opts = GlobalTestOptions { no_crate_inject: true, ..default_global_opts("asdf") }; let input = "use asdf::qwop; assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] @@ -72,7 +84,7 @@ fn make_test_ignore_std() { // Even if you include a crate name, and use it in the doctest, we still won't include an // `extern crate` statement if the crate is "std" -- that's included already by the // compiler! - let opts = GlobalTestOptions::default(); + let opts = default_global_opts("std"); let input = "use std::*; assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] @@ -89,7 +101,7 @@ assert_eq!(2+2, 4); fn make_test_manual_extern_crate() { // When you manually include an `extern crate` statement in your doctest, `make_test` // assumes you've included one for your own crate too. - let opts = GlobalTestOptions::default(); + let opts = default_global_opts("asdf"); let input = "extern crate asdf; use asdf::qwop; assert_eq!(2+2, 4);"; @@ -106,7 +118,7 @@ assert_eq!(2+2, 4); #[test] fn make_test_manual_extern_crate_with_macro_use() { - let opts = GlobalTestOptions::default(); + let opts = default_global_opts("asdf"); let input = "#[macro_use] extern crate asdf; use asdf::qwop; assert_eq!(2+2, 4);"; @@ -125,7 +137,7 @@ assert_eq!(2+2, 4); fn make_test_opts_attrs() { // If you supplied some doctest attributes with `#![doc(test(attr(...)))]`, it will use // those instead of the stock `#![allow(unused)]`. - let mut opts = GlobalTestOptions::default(); + let mut opts = default_global_opts("asdf"); opts.attrs.push("feature(sick_rad)".to_string()); let input = "use asdf::qwop; assert_eq!(2+2, 4);"; @@ -159,7 +171,7 @@ assert_eq!(2+2, 4); fn make_test_crate_attrs() { // Including inner attributes in your doctest will apply them to the whole "crate", pasting // them outside the generated main function. - let opts = GlobalTestOptions::default(); + let opts = default_global_opts(""); let input = "#![feature(sick_rad)] assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] @@ -175,7 +187,7 @@ assert_eq!(2+2, 4); #[test] fn make_test_with_main() { // Including your own `fn main` wrapper lets the test use it verbatim. - let opts = GlobalTestOptions::default(); + let opts = default_global_opts(""); let input = "fn main() { assert_eq!(2+2, 4); }"; @@ -191,7 +203,7 @@ fn main() { #[test] fn make_test_fake_main() { // ... but putting it in a comment will still provide a wrapper. - let opts = GlobalTestOptions::default(); + let opts = default_global_opts(""); let input = "//Ceci n'est pas une `fn main` assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] @@ -207,7 +219,7 @@ assert_eq!(2+2, 4); #[test] fn make_test_dont_insert_main() { // Even with that, if you set `dont_insert_main`, it won't create the `fn main` wrapper. - let opts = GlobalTestOptions::default(); + let opts = default_global_opts(""); let input = "//Ceci n'est pas une `fn main` assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] @@ -219,8 +231,8 @@ assert_eq!(2+2, 4);" } #[test] -fn make_test_issues_21299_33731() { - let opts = GlobalTestOptions::default(); +fn make_test_issues_21299() { + let opts = default_global_opts(""); let input = "// fn main assert_eq!(2+2, 4);"; @@ -234,6 +246,11 @@ assert_eq!(2+2, 4); let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); assert_eq!((output, len), (expected, 2)); +} + +#[test] +fn make_test_issues_33731() { + let opts = default_global_opts("asdf"); let input = "extern crate hella_qwop; assert_eq!(asdf::foo, 4);"; @@ -253,7 +270,7 @@ assert_eq!(asdf::foo, 4); #[test] fn make_test_main_in_macro() { - let opts = GlobalTestOptions::default(); + let opts = default_global_opts("my_crate"); let input = "#[macro_use] extern crate my_crate; test_wrapper! { fn main() {} @@ -272,7 +289,7 @@ test_wrapper! { #[test] fn make_test_returns_result() { // creates an inner function and unwraps it - let opts = GlobalTestOptions::default(); + let opts = default_global_opts(""); let input = "use std::io; let mut input = String::new(); io::stdin().read_line(&mut input)?; @@ -292,7 +309,7 @@ Ok::<(), io:Error>(()) #[test] fn make_test_named_wrapper() { // creates an inner function with a specific name - let opts = GlobalTestOptions::default(); + let opts = default_global_opts(""); let input = "assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] fn main() { #[allow(non_snake_case)] fn _doctest_main__some_unique_name() { @@ -307,8 +324,7 @@ assert_eq!(2+2, 4); #[test] fn make_test_insert_extra_space() { // will insert indent spaces in the code block if `insert_indent_space` is true - let opts = - GlobalTestOptions { no_crate_inject: false, attrs: vec![], insert_indent_space: true }; + let opts = GlobalTestOptions { insert_indent_space: true, ..default_global_opts("") }; let input = "use std::*; assert_eq!(2+2, 4); eprintln!(\"hello anan\"); @@ -327,8 +343,7 @@ fn main() { #[test] fn make_test_insert_extra_space_fn_main() { // if input already has a fn main, it should insert a space before it - let opts = - GlobalTestOptions { no_crate_inject: false, attrs: vec![], insert_indent_space: true }; + let opts = GlobalTestOptions { insert_indent_space: true, ..default_global_opts("") }; let input = "use std::*; fn main() { assert_eq!(2+2, 4); diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index cf11e2d7899..c85b955d4c5 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -79,7 +79,7 @@ pub(crate) trait DocFolder: Sized { | FunctionItem(_) | OpaqueTyItem(_) | StaticItem(_) - | ConstantItem(_) + | ConstantItem(_, _, _) | TraitAliasItem(_) | TyMethodItem(_) | MethodItem(_, _) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 28ddf76a3a6..a3b88a880f2 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -155,7 +155,7 @@ impl Cache { // Cache where all our extern crates are located // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code - for &crate_num in tcx.crates_including_speculative(()) { + for &crate_num in tcx.crates(()) { let e = ExternalCrate { crate_num }; let name = e.name(tcx); diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index d20cef745ab..4268fadd6c5 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1438,13 +1438,9 @@ impl clean::FnDecl { { write!(f, "\n{}", Indent(n + 4))?; } + + let last_input_index = self.inputs.values.len().checked_sub(1); for (i, input) in self.inputs.values.iter().enumerate() { - if i > 0 { - match line_wrapping_indent { - None => write!(f, ", ")?, - Some(n) => write!(f, ",\n{}", Indent(n + 4))?, - }; - } if let Some(selfty) = input.to_self() { match selfty { clean::SelfValue => { @@ -1477,18 +1473,25 @@ impl clean::FnDecl { write!(f, "{}: ", input.name)?; input.type_.print(cx).fmt(f)?; } + match (line_wrapping_indent, last_input_index) { + (_, None) => (), + (None, Some(last_i)) if i != last_i => write!(f, ", ")?, + (None, Some(_)) => (), + (Some(n), Some(last_i)) if i != last_i => write!(f, ",\n{}", Indent(n + 4))?, + (Some(_), Some(_)) => write!(f, ",\n")?, + } } if self.c_variadic { match line_wrapping_indent { None => write!(f, ", ...")?, - Some(n) => write!(f, "\n{}...", Indent(n + 4))?, + Some(n) => write!(f, "{}...\n", Indent(n + 4))?, }; } match line_wrapping_indent { None => write!(f, ")")?, - Some(n) => write!(f, "\n{})", Indent(n))?, + Some(n) => write!(f, "{})", Indent(n))?, }; self.print_output(cx).fmt(f) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 11cc81700ff..bae929c64ea 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -39,6 +39,7 @@ use std::collections::VecDeque; use std::fmt::Write; use std::iter::Peekable; use std::ops::{ControlFlow, Range}; +use std::path::PathBuf; use std::str::{self, CharIndices}; use std::sync::OnceLock; @@ -287,8 +288,15 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { .collect::<String>(); let krate = krate.as_ref().map(|s| s.as_str()); - let mut opts: GlobalTestOptions = Default::default(); - opts.insert_indent_space = true; + // FIXME: separate out the code to make a code block into runnable code + // from the complicated doctest logic + let opts = GlobalTestOptions { + crate_name: krate.map(String::from).unwrap_or_default(), + no_crate_inject: false, + insert_indent_space: true, + attrs: vec![], + args_file: PathBuf::new(), + }; let (test, _, _) = doctest::make_test(&test, krate, false, &opts, edition, None); let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" }; @@ -710,7 +718,29 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> { } } -pub(crate) fn find_testable_code<T: doctest::Tester>( +/// A newtype that represents a relative line number in Markdown. +/// +/// In other words, this represents an offset from the first line of Markdown +/// in a doc comment or other source. If the first Markdown line appears on line 32, +/// and the `MdRelLine` is 3, then the absolute line for this one is 35. I.e., it's +/// a zero-based offset. +pub(crate) struct MdRelLine { + offset: usize, +} + +impl MdRelLine { + /// See struct docs. + pub(crate) const fn new(offset: usize) -> Self { + Self { offset } + } + + /// See struct docs. + pub(crate) const fn offset(self) -> usize { + self.offset + } +} + +pub(crate) fn find_testable_code<T: doctest::DoctestVisitor>( doc: &str, tests: &mut T, error_codes: ErrorCodes, @@ -720,7 +750,7 @@ pub(crate) fn find_testable_code<T: doctest::Tester>( find_codes(doc, tests, error_codes, enable_per_target_ignores, extra_info, false) } -pub(crate) fn find_codes<T: doctest::Tester>( +pub(crate) fn find_codes<T: doctest::DoctestVisitor>( doc: &str, tests: &mut T, error_codes: ErrorCodes, @@ -772,8 +802,8 @@ pub(crate) fn find_codes<T: doctest::Tester>( if nb_lines != 0 && !&doc[prev_offset..offset.start].ends_with('\n') { nb_lines -= 1; } - let line = tests.get_line() + nb_lines + 1; - tests.add_test(text, block_info, line); + let line = MdRelLine::new(nb_lines); + tests.visit_test(text, block_info, line); prev_offset = offset.start; } Event::Start(Tag::Heading(level, _, _)) => { @@ -781,7 +811,7 @@ pub(crate) fn find_codes<T: doctest::Tester>( } Event::Text(ref s) if register_header.is_some() => { let level = register_header.unwrap(); - tests.register_header(s, level); + tests.visit_header(s, level); register_header = None; } _ => {} diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index c5b88c7a951..e1f79254b24 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -266,7 +266,7 @@ pub(super) fn print_item(cx: &mut Context<'_>, item: &clean::Item, buf: &mut Buf clean::ProcMacroItem(ref m) => item_proc_macro(buf, cx, item, m), clean::PrimitiveItem(_) => item_primitive(buf, cx, item), clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => item_static(buf, cx, item, i), - clean::ConstantItem(ref c) => item_constant(buf, cx, item, c), + clean::ConstantItem(generics, ty, c) => item_constant(buf, cx, item, generics, ty, c), clean::ForeignTypeItem => item_foreign_type(buf, cx, item), clean::KeywordItem => item_keyword(buf, cx, item), clean::OpaqueTyItem(ref e) => item_opaque_ty(buf, cx, item, e), @@ -1844,7 +1844,14 @@ fn item_primitive(w: &mut impl fmt::Write, cx: &mut Context<'_>, it: &clean::Ite } } -fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) { +fn item_constant( + w: &mut Buffer, + cx: &mut Context<'_>, + it: &clean::Item, + generics: &clean::Generics, + ty: &clean::Type, + c: &clean::Constant, +) { wrap_item(w, |w| { let tcx = cx.tcx(); render_attributes_in_code(w, it, cx); @@ -1854,9 +1861,9 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle "{vis}const {name}{generics}: {typ}{where_clause}", vis = visibility_print_with_space(it, cx), name = it.name.unwrap(), - generics = c.generics.print(cx), - typ = c.type_.print(cx), - where_clause = print_where_clause(&c.generics, cx, 0, Ending::NoNewline), + generics = generics.print(cx), + typ = ty.print(cx), + where_clause = print_where_clause(&generics, cx, 0, Ending::NoNewline), ); // FIXME: The code below now prints diff --git a/src/librustdoc/html/static/.eslintrc.js b/src/librustdoc/html/static/.eslintrc.js index a1e9cc6dfa1..fbb096fe9c7 100644 --- a/src/librustdoc/html/static/.eslintrc.js +++ b/src/librustdoc/html/static/.eslintrc.js @@ -5,7 +5,7 @@ module.exports = { }, "extends": "eslint:recommended", "parserOptions": { - "ecmaVersion": 8, + "ecmaVersion": 2019, "sourceType": "module" }, "rules": { diff --git a/src/librustdoc/html/static/js/externs.js b/src/librustdoc/html/static/js/externs.js index 8cebce7ae86..6fd60d6cc34 100644 --- a/src/librustdoc/html/static/js/externs.js +++ b/src/librustdoc/html/static/js/externs.js @@ -41,8 +41,9 @@ let ParserState; * foundElems: number, * totalElems: number, * literalSearch: boolean, - * corrections: Array<{from: string, to: integer}>, + * corrections: Array<{from: string, to: integer}> | null, * typeFingerprint: Uint32Array, + * error: Array<string> | null, * }} */ let ParsedQuery; diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 76a6fc9008e..a0ab262bf0b 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -89,6 +89,10 @@ const ROOT_PATH = typeof window !== "undefined" ? window.rootPath : "../"; // of permutations we need to check. const UNBOXING_LIMIT = 5; +// used for search query verification +const REGEX_IDENT = /\p{ID_Start}\p{ID_Continue}*|_\p{ID_Continue}+/uy; +const REGEX_INVALID_TYPE_FILTER = /[^a-z]/ui; + // In the search display, allows to switch between tabs. function printTab(nb) { let iter = 0; @@ -410,18 +414,21 @@ function initSearch(rawSearchIndex) { } /** - * Returns `true` if the given `c` character is valid for an ident. + * If the current parser position is at the beginning of an identifier, + * move the position to the end of it and return `true`. Otherwise, return `false`. * - * @param {string} c + * @param {ParserState} parserState * * @return {boolean} */ - function isIdentCharacter(c) { - return ( - c === "_" || - (c >= "0" && c <= "9") || - (c >= "a" && c <= "z") || - (c >= "A" && c <= "Z")); + function consumeIdent(parserState) { + REGEX_IDENT.lastIndex = parserState.pos; + const match = parserState.userQuery.match(REGEX_IDENT); + if (match) { + parserState.pos += match[0].length; + return true; + } + return false; } /** @@ -618,70 +625,62 @@ function initSearch(rawSearchIndex) { * @return {integer} */ function getIdentEndPosition(parserState) { - const start = parserState.pos; + let afterIdent = consumeIdent(parserState); let end = parserState.pos; - let foundExclamation = -1; + let macroExclamation = -1; while (parserState.pos < parserState.length) { const c = parserState.userQuery[parserState.pos]; - if (!isIdentCharacter(c)) { - if (c === "!") { - if (foundExclamation !== -1) { - throw ["Cannot have more than one ", "!", " in an ident"]; - } else if (parserState.pos + 1 < parserState.length && - isIdentCharacter(parserState.userQuery[parserState.pos + 1]) - ) { + if (c === "!") { + if (macroExclamation !== -1) { + throw ["Cannot have more than one ", "!", " in an ident"]; + } else if (parserState.pos + 1 < parserState.length) { + const pos = parserState.pos; + parserState.pos++; + const beforeIdent = consumeIdent(parserState); + parserState.pos = pos; + if (beforeIdent) { throw ["Unexpected ", "!", ": it can only be at the end of an ident"]; } - foundExclamation = parserState.pos; - } else if (isPathSeparator(c)) { - if (c === ":") { - if (!isPathStart(parserState)) { + } + if (afterIdent) macroExclamation = parserState.pos; + } else if (isPathSeparator(c)) { + if (c === ":") { + if (!isPathStart(parserState)) { + break; + } + // Skip current ":". + parserState.pos += 1; + } else { + while (parserState.pos + 1 < parserState.length) { + const next_c = parserState.userQuery[parserState.pos + 1]; + if (next_c !== " ") { break; } - // Skip current ":". parserState.pos += 1; - } else { - while (parserState.pos + 1 < parserState.length) { - const next_c = parserState.userQuery[parserState.pos + 1]; - if (next_c !== " ") { - break; - } - parserState.pos += 1; - } } - if (foundExclamation !== -1) { - if (foundExclamation !== start && - isIdentCharacter(parserState.userQuery[foundExclamation - 1]) - ) { - throw ["Cannot have associated items in macros"]; - } else { - // while the never type has no associated macros, we still - // can parse a path like that - foundExclamation = -1; - } - } - } else if ( - c === "[" || - c === "(" || - isEndCharacter(c) || - isSpecialStartCharacter(c) || - isSeparatorCharacter(c) - ) { - break; - } else if (parserState.pos > 0) { - throw ["Unexpected ", c, " after ", parserState.userQuery[parserState.pos - 1]]; - } else { - throw ["Unexpected ", c]; } + if (macroExclamation !== -1) { + throw ["Cannot have associated items in macros"]; + } + } else if ( + c === "[" || + c === "(" || + isEndCharacter(c) || + isSpecialStartCharacter(c) || + isSeparatorCharacter(c) + ) { + break; + } else if (parserState.pos > 0) { + throw ["Unexpected ", c, " after ", parserState.userQuery[parserState.pos - 1], + " (not a valid identifier)"]; + } else { + throw ["Unexpected ", c, " (not a valid identifier)"]; } parserState.pos += 1; + afterIdent = consumeIdent(parserState); end = parserState.pos; } - // if start == end - 1, we got the never type - if (foundExclamation !== -1 && - foundExclamation !== start && - isIdentCharacter(parserState.userQuery[foundExclamation - 1]) - ) { + if (macroExclamation !== -1) { if (parserState.typeFilter === null) { parserState.typeFilter = "macro"; } else if (parserState.typeFilter !== "macro") { @@ -693,7 +692,7 @@ function initSearch(rawSearchIndex) { " both specified", ]; } - end = foundExclamation; + end = macroExclamation; } return end; } @@ -1071,16 +1070,15 @@ function initSearch(rawSearchIndex) { function checkExtraTypeFilterCharacters(start, parserState) { const query = parserState.userQuery.slice(start, parserState.pos).trim(); - for (const c in query) { - if (!isIdentCharacter(query[c])) { - throw [ - "Unexpected ", - query[c], - " in type filter (before ", - ":", - ")", - ]; - } + const match = query.match(REGEX_INVALID_TYPE_FILTER); + if (match) { + throw [ + "Unexpected ", + match[0], + " in type filter (before ", + ":", + ")", + ]; } } @@ -2127,7 +2125,7 @@ function initSearch(rawSearchIndex) { }; } - function handleAliases(ret, query, filterCrates, currentCrate) { + async function handleAliases(ret, query, filterCrates, currentCrate) { const lowerQuery = query.toLowerCase(); // We separate aliases and crate aliases because we want to have current crate // aliases to be before the others in the displayed results. @@ -2163,6 +2161,15 @@ function initSearch(rawSearchIndex) { crateAliases.sort(sortFunc); aliases.sort(sortFunc); + const fetchDesc = alias => { + return searchIndexEmptyDesc.get(alias.crate).contains(alias.bitIndex) ? + "" : searchState.loadDesc(alias); + }; + const [crateDescs, descs] = await Promise.all([ + Promise.all(crateAliases.map(fetchDesc)), + Promise.all(aliases.map(fetchDesc)), + ]); + const pushFunc = alias => { alias.alias = query; const res = buildHrefAndPath(alias); @@ -2176,7 +2183,13 @@ function initSearch(rawSearchIndex) { } }; + aliases.forEach((alias, i) => { + alias.desc = descs[i]; + }); aliases.forEach(pushFunc); + crateAliases.forEach((alias, i) => { + alias.desc = crateDescs[i]; + }); crateAliases.forEach(pushFunc); } @@ -2386,15 +2399,19 @@ function initSearch(rawSearchIndex) { * @param {boolean} isAssocType */ function convertNameToId(elem, isAssocType) { - if (typeNameIdMap.has(elem.normalizedPathLast) && - (isAssocType || !typeNameIdMap.get(elem.normalizedPathLast).assocOnly)) { - elem.id = typeNameIdMap.get(elem.normalizedPathLast).id; + const loweredName = elem.pathLast.toLowerCase(); + if (typeNameIdMap.has(loweredName) && + (isAssocType || !typeNameIdMap.get(loweredName).assocOnly)) { + elem.id = typeNameIdMap.get(loweredName).id; } else if (!parsedQuery.literalSearch) { let match = null; let matchDist = maxEditDistance + 1; let matchName = ""; for (const [name, {id, assocOnly}] of typeNameIdMap) { - const dist = editDistance(name, elem.normalizedPathLast, maxEditDistance); + const dist = Math.min( + editDistance(name, loweredName, maxEditDistance), + editDistance(name, elem.normalizedPathLast, maxEditDistance), + ); if (dist <= matchDist && dist <= maxEditDistance && (isAssocType || !assocOnly)) { if (dist === matchDist && matchName > name) { @@ -2538,7 +2555,8 @@ function initSearch(rawSearchIndex) { sorted_returned, sorted_others, parsedQuery); - handleAliases(ret, parsedQuery.original.replace(/"/g, ""), filterCrates, currentCrate); + await handleAliases(ret, parsedQuery.original.replace(/"/g, ""), + filterCrates, currentCrate); await Promise.all([ret.others, ret.returned, ret.in_args].map(async list => { const descs = await Promise.all(list.map(result => { return searchIndexEmptyDesc.get(result.crate).contains(result.bitIndex) ? diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 7e6a19aa52e..afafb4fbe4b 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -183,7 +183,7 @@ impl FromWithTcx<clean::Constant> for Constant { let expr = constant.expr(tcx); let value = constant.value(tcx); let is_literal = constant.is_literal(tcx); - Constant { type_: (*constant.type_).into_tcx(tcx), expr, value, is_literal } + Constant { expr, value, is_literal } } } @@ -321,7 +321,10 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum { ForeignTypeItem => ItemEnum::ForeignType, TypeAliasItem(t) => ItemEnum::TypeAlias(t.into_tcx(tcx)), OpaqueTyItem(t) => ItemEnum::OpaqueTy(t.into_tcx(tcx)), - ConstantItem(c) => ItemEnum::Constant(c.into_tcx(tcx)), + // FIXME(generic_const_items): Add support for generic free consts + ConstantItem(_generics, t, c) => { + ItemEnum::Constant { type_: (*t).into_tcx(tcx), const_: c.into_tcx(tcx) } + } MacroItem(m) => ItemEnum::Macro(m.source), ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_tcx(tcx)), PrimitiveItem(p) => { diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index c1d90020e87..0ef24818515 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -186,7 +186,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { | types::ItemEnum::Impl(_) | types::ItemEnum::TypeAlias(_) | types::ItemEnum::OpaqueTy(_) - | types::ItemEnum::Constant(_) + | types::ItemEnum::Constant { .. } | types::ItemEnum::Static(_) | types::ItemEnum::ForeignType | types::ItemEnum::Macro(_) diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index c0d2f9cfaf9..d6e715d48ea 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -555,6 +555,14 @@ fn opts() -> Vec<RustcOptGroup> { unstable("no-run", |o| { o.optflagmulti("", "no-run", "Compile doctests without running them") }), + unstable("remap-path-prefix", |o| { + o.optmulti( + "", + "remap-path-prefix", + "Remap source names in compiler messages", + "FROM=TO", + ) + }), unstable("show-type-layout", |o| { o.optflagmulti("", "show-type-layout", "Include the memory layout of types in the docs") }), @@ -728,7 +736,7 @@ fn main_args( core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts); match (options.should_test, options.markdown_input()) { - (true, Some(_)) => return wrap_return(&diag, markdown::test(options)), + (true, Some(_)) => return wrap_return(&diag, doctest::test_markdown(options)), (true, None) => return doctest::run(&diag, options), (false, Some(input)) => { let input = input.to_owned(); diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index bcc5a37618a..a98f81d011e 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -3,18 +3,12 @@ use std::fs::{create_dir_all, read_to_string, File}; use std::io::prelude::*; use std::path::Path; -use tempfile::tempdir; - use rustc_span::edition::Edition; -use rustc_span::DUMMY_SP; -use crate::config::{Options, RenderOptions}; -use crate::doctest::{generate_args_file, Collector, GlobalTestOptions}; +use crate::config::RenderOptions; use crate::html::escape::Escape; use crate::html::markdown; -use crate::html::markdown::{ - find_testable_code, ErrorCodes, HeadingOffset, IdMap, Markdown, MarkdownWithToc, -}; +use crate::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, MarkdownWithToc}; /// Separate any lines at the start of the file that begin with `# ` or `%`. fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) { @@ -137,41 +131,3 @@ pub(crate) fn render<P: AsRef<Path>>( Ok(_) => Ok(()), } } - -/// Runs any tests/code examples in the markdown file `input`. -pub(crate) fn test(options: Options) -> Result<(), String> { - use rustc_session::config::Input; - let input_str = match &options.input { - Input::File(path) => { - read_to_string(&path).map_err(|err| format!("{}: {err}", path.display()))? - } - Input::Str { name: _, input } => input.clone(), - }; - - let mut opts = GlobalTestOptions::default(); - opts.no_crate_inject = true; - - let temp_dir = - tempdir().map_err(|error| format!("failed to create temporary directory: {error:?}"))?; - let file_path = temp_dir.path().join("rustdoc-cfgs"); - generate_args_file(&file_path, &options)?; - - let mut collector = Collector::new( - options.input.filestem().to_string(), - options.clone(), - true, - opts, - None, - options.input.opt_path().map(ToOwned::to_owned), - options.enable_per_target_ignores, - file_path, - ); - collector.set_position(DUMMY_SP); - let codes = ErrorCodes::from(options.unstable_features.is_nightly_build()); - - // For markdown files, custom code classes will be disabled until the feature is enabled by default. - find_testable_code(&input_str, &mut collector, codes, options.enable_per_target_ignores, None); - - crate::doctest::run_tests(options.test_args, options.nocapture, collector.tests); - Ok(()) -} diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index 02589a137b4..0437f5e5fd8 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -10,7 +10,7 @@ use crate::clean; use crate::clean::utils::inherits_doc_hidden; use crate::clean::*; use crate::core::DocContext; -use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString}; +use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString, MdRelLine}; use crate::visit::DocVisitor; use rustc_hir as hir; use rustc_middle::lint::LintLevelSource; @@ -44,8 +44,8 @@ pub(crate) struct Tests { pub(crate) found_tests: usize, } -impl crate::doctest::Tester for Tests { - fn add_test(&mut self, _: String, config: LangString, _: usize) { +impl crate::doctest::DoctestVisitor for Tests { + fn visit_test(&mut self, _: String, config: LangString, _: MdRelLine) { if config.rust && config.ignore == Ignore::None { self.found_tests += 1; } @@ -62,7 +62,7 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) - | clean::AssocTypeItem(..) | clean::TypeAliasItem(_) | clean::StaticItem(_) - | clean::ConstantItem(_) + | clean::ConstantItem(_, _, _) | clean::ExternCrateItem { .. } | clean::ImportItem(_) | clean::PrimitiveItem(_) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 8ab24a8c12e..440b02a1fa7 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -12,7 +12,7 @@ use rustc_errors::{Applicability, Diag, DiagMessage}; use rustc_hir::def::Namespace::*; use rustc_hir::def::{DefKind, Namespace, PerNS}; use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; -use rustc_hir::Mutability; +use rustc_hir::{Mutability, Safety}; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_middle::{bug, span_bug, ty}; use rustc_resolve::rustdoc::{has_primitive_or_keyword_docs, prepare_to_doc_link_resolution}; @@ -1517,7 +1517,11 @@ impl Disambiguator { "union" => Kind(DefKind::Union), "module" | "mod" => Kind(DefKind::Mod), "const" | "constant" => Kind(DefKind::Const), - "static" => Kind(DefKind::Static { mutability: Mutability::Not, nested: false }), + "static" => Kind(DefKind::Static { + mutability: Mutability::Not, + nested: false, + safety: Safety::Safe, + }), "function" | "fn" | "method" => Kind(DefKind::Fn), "derive" => Kind(DefKind::Macro(MacroKind::Derive)), "type" => NS(Namespace::TypeNS), diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 22daac9efb1..c92cf9d3e80 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -47,7 +47,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> // External trait impls. { let _prof_timer = tcx.sess.prof.generic_activity("build_extern_trait_impls"); - for &cnum in tcx.crates_including_speculative(()) { + for &cnum in tcx.crates(()) { for &impl_def_id in tcx.trait_impls_in_crate(cnum) { cx.with_param_env(impl_def_id, |cx| { inline::build_impl(cx, impl_def_id, None, &mut new_items_external); diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index 39350f4cbbb..c185442fd55 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -5,7 +5,7 @@ use rustc_errors::{ translation::{to_fluent_args, Translate}, Applicability, DiagCtxt, DiagInner, LazyFallbackBundle, }; -use rustc_parse::parse_stream_from_source_str; +use rustc_parse::{source_str_to_stream, unwrap_or_emit_fatal}; use rustc_resolve::rustdoc::source_span_for_markdown_range; use rustc_session::parse::ParseSess; use rustc_span::hygiene::{AstPass, ExpnData, ExpnKind, LocalExpnId, Transparency}; @@ -51,12 +51,12 @@ fn check_rust_syntax( let span = DUMMY_SP.apply_mark(expn_id.to_expn_id(), Transparency::Transparent); let is_empty = rustc_driver::catch_fatal_errors(|| { - parse_stream_from_source_str( + unwrap_or_emit_fatal(source_str_to_stream( + &psess, FileName::Custom(String::from("doctest")), source, - &psess, Some(span), - ) + )) .is_empty() }) .unwrap_or(false); diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index 64753a58a2b..e9b380fdeac 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -283,7 +283,7 @@ pub(crate) fn run( // Collect CrateIds corresponding to provided target crates // If two different versions of the crate in the dependency tree, then examples will be collected from both. let all_crates = tcx - .crates_including_speculative(()) + .crates(()) .iter() .chain([&LOCAL_CRATE]) .map(|crate_num| (crate_num, tcx.crate_name(*crate_num))) diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs index 01e6cb4b93b..0660037e4d8 100644 --- a/src/librustdoc/visit.rs +++ b/src/librustdoc/visit.rs @@ -28,7 +28,7 @@ pub(crate) trait DocVisitor: Sized { | TypeAliasItem(_) | OpaqueTyItem(_) | StaticItem(_) - | ConstantItem(_) + | ConstantItem(_, _, _) | TraitAliasItem(_) | TyMethodItem(_) | MethodItem(_, _) diff --git a/src/llvm-project b/src/llvm-project -Subproject b31c30a9bb4dbbd13c359d0e2bea7f65d20adf3 +Subproject 5a5152f653959d14d68613a3a8a033fb65eec02 diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 1c5a6dcfb1f..68030493e9c 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use std::path::PathBuf; /// rustdoc format-version. -pub const FORMAT_VERSION: u32 = 29; +pub const FORMAT_VERSION: u32 = 30; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow @@ -167,8 +167,6 @@ pub enum GenericArg { #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct Constant { - #[serde(rename = "type")] - pub type_: Type, pub expr: String, pub value: Option<String>, pub is_literal: bool, @@ -256,7 +254,12 @@ pub enum ItemEnum { TypeAlias(TypeAlias), OpaqueTy(OpaqueTy), - Constant(Constant), + Constant { + #[serde(rename = "type")] + type_: Type, + #[serde(rename = "const")] + const_: Constant, + }, Static(Static), diff --git a/src/tools/build_helper/README.md b/src/tools/build_helper/README.md new file mode 100644 index 00000000000..f81b631c3fd --- /dev/null +++ b/src/tools/build_helper/README.md @@ -0,0 +1 @@ +Types and functions shared across tools in this workspace. diff --git a/src/tools/build_helper/src/lib.rs b/src/tools/build_helper/src/lib.rs index 2abda5d3ebf..15807d1c0d8 100644 --- a/src/tools/build_helper/src/lib.rs +++ b/src/tools/build_helper/src/lib.rs @@ -1,5 +1,30 @@ +//! Types and functions shared across tools in this workspace. + pub mod ci; pub mod git; pub mod metrics; pub mod stage0_parser; pub mod util; + +/// The default set of crates for opt-dist to collect LLVM profiles. +pub const LLVM_PGO_CRATES: &[&str] = &[ + "syn-1.0.89", + "cargo-0.60.0", + "serde-1.0.136", + "ripgrep-13.0.0", + "regex-1.5.5", + "clap-3.1.6", + "hyper-0.14.18", +]; + +/// The default set of crates for opt-dist to collect rustc profiles. +pub const RUSTC_PGO_CRATES: &[&str] = &[ + "externs", + "ctfe-stress-5", + "cargo-0.60.0", + "token-stream-stress", + "match-stress", + "tuple-stress", + "diesel-1.4.8", + "bitmaps-3.1.0", +]; diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 7a6fad0984d28c8330974636972aa296b67c451 +Subproject b1feb75d062444e2cee8b3d2aaa95309d65e9cc diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs index 651f2ebaee6..c3e3c0431e6 100644 --- a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs +++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs @@ -8,7 +8,7 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::HumanEmitter; use rustc_errors::{Diag, DiagCtxt}; use rustc_lint::LateContext; -use rustc_parse::maybe_new_parser_from_source_str; +use rustc_parse::new_parser_from_source_str; use rustc_parse::parser::ForceCollect; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; @@ -50,7 +50,7 @@ pub fn check( let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let psess = ParseSess::with_dcx(dcx, sm); - let mut parser = match maybe_new_parser_from_source_str(&psess, filename, code) { + let mut parser = match new_parser_from_source_str(&psess, filename, code) { Ok(p) => p, Err(errs) => { errs.into_iter().for_each(Diag::cancel); 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 192fb611c2d..cb1d0de1edf 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -79,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap(); let span = decl.output.span(); let infcx = cx.tcx.infer_ctxt().build(); - let ocx = ObligationCtxt::new(&infcx); + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); let cause = traits::ObligationCause::misc(span, fn_def_id); ocx.register_bound(cause, cx.param_env, ret_ty, send_trait); let send_errors = ocx.select_all_or_error(); diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs index b561054b582..7f8197c0cc0 100644 --- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs @@ -54,8 +54,8 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays { && generics.params.is_empty() && !generics.has_where_clause_predicates && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity() && let ty::Array(element_type, cst) = ty.kind() - && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() - && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) + && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind() + && let element_count = element_count.to_target_usize(cx.tcx) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) { diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs index 208d1bb6e68..c9bfc9c85d9 100644 --- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs +++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs @@ -64,8 +64,8 @@ impl<'tcx> LateLintPass<'tcx> for LargeStackArrays { if let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind && !self.is_from_vec_macro(cx, expr.span) && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind() - && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() - && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) + && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind() + && let element_count = element_count.to_target_usize(cx.tcx) && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes()) && !cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, node)| { matches!( diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs index 8199366d175..45b375dbe3d 100644 --- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs @@ -37,14 +37,14 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) Some(lhs) => constant(cx, cx.typeck_results(), lhs)?, None => { let min_val_const = ty.numeric_min_val(cx.tcx)?; - mir_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))? + mir_to_const(cx, mir::Const::from_ty_const(min_val_const, ty, cx.tcx))? }, }; let rhs_const = match rhs { Some(rhs) => constant(cx, cx.typeck_results(), rhs)?, None => { let max_val_const = ty.numeric_max_val(cx.tcx)?; - mir_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))? + mir_to_const(cx, mir::Const::from_ty_const(max_val_const, ty, cx.tcx))? }, }; let lhs_val = lhs_const.int_value(cx, ty)?; diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs index f4397212cf6..7f6b666e434 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_on_single_or_empty_collections.rs @@ -42,7 +42,7 @@ fn is_arg_ty_unified_in_fn<'tcx>( cx.tcx.predicates_of(fn_id).predicates.iter().any(|(clause, _)| { clause .as_projection_clause() - .and_then(|p| p.map_bound(|p| p.term.ty()).transpose()) + .and_then(|p| p.map_bound(|p| p.term.as_type()).transpose()) .is_some_and(|ty| ty.skip_binder() == arg_ty_in_args) }) || fn_sig .inputs() 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 5b5e1c23424..4f99eaa40c2 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 @@ -311,7 +311,7 @@ fn is_mixed_projection_predicate<'tcx>( ) -> bool { let generics = cx.tcx.generics_of(callee_def_id); // The predicate requires the projected type to equal a type parameter from the parent context. - if let Some(term_ty) = projection_predicate.term.ty() + if let Some(term_ty) = projection_predicate.term.as_type() && let ty::Param(term_param_ty) = term_ty.kind() && (term_param_ty.index as usize) < generics.parent_count { @@ -370,7 +370,7 @@ fn replace_types<'tcx>( if replaced.insert(param_ty.index) { for projection_predicate in projection_predicates { if projection_predicate.projection_term.self_ty() == param_ty.to_ty(cx.tcx) - && let Some(term_ty) = projection_predicate.term.ty() + && let Some(term_ty) = projection_predicate.term.as_type() && let ty::Param(term_param_ty) = term_ty.kind() { let projection = projection_predicate diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 76d9cee18aa..20a97645af9 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -199,7 +199,7 @@ impl<'tcx> NonCopyConst<'tcx> { .any(|field| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), ty::Adt(def, args) if def.is_enum() => { let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap(); - let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap()); + let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().to_u32()); fields .iter() .copied() diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs index f0d1458a59b..a8cc2f97963 100644 --- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs +++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs @@ -100,12 +100,12 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve { if ord_preds .iter() - .any(|ord| Some(ord.self_ty()) == return_ty_pred.term.ty()) + .any(|ord| Some(ord.self_ty()) == return_ty_pred.term.as_type()) { args_to_check.push((i, "Ord".to_string())); } else if partial_ord_preds .iter() - .any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap()) + .any(|pord| pord.self_ty() == return_ty_pred.term.expect_type()) { args_to_check.push((i, "PartialOrd".to_string())); } diff --git a/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs b/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs index 143fecdd237..8796b8f61d1 100644 --- a/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/zero_repeat_side_effects.rs @@ -55,9 +55,8 @@ impl LateLintPass<'_> for ZeroRepeatSideEffects { inner_check(cx, expr, inner_expr, true); } else if let ExprKind::Repeat(inner_expr, _) = expr.kind && let ty::Array(_, cst) = cx.typeck_results().expr_ty(expr).kind() - && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind() - && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx) - && element_count == 0 + && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind() + && element_count.to_target_usize(cx.tcx) == 0 { inner_check(cx, expr, inner_expr, false); } diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index bbdde3049db..c70f5c2df84 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -308,13 +308,15 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { ty: lt, mutability: lm, expr: le, + safety: ls, }), Static(box StaticItem { ty: rt, mutability: rm, expr: re, + safety: rs, }), - ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), + ) => lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le, re), ( Const(box ConstItem { defaultness: ld, @@ -451,13 +453,15 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { ty: lt, mutability: lm, expr: le, + safety: ls, }), Static(box StaticForeignItem { ty: rt, mutability: rm, expr: re, + safety: rs, }), - ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re), + ) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re) && ls == rs, ( Fn(box ast::Fn { defaultness: ld, diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index cd88ccd87cf..e9e1aa7e445 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -6,7 +6,7 @@ use crate::{clip, is_direct_expn_of, sext, unsext}; use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_data_structures::sync::Lrc; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; +use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; use rustc_lexer::tokenize; use rustc_lint::LateContext; use rustc_middle::mir::interpret::{alloc_range, Scalar}; @@ -412,7 +412,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// Simple constant folding: Insert an expression, get a constant or none. pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant<'tcx>> { match e.kind { - ExprKind::ConstBlock(e) | ExprKind::DropTemps(e) => self.expr(e), + ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value), ExprKind::DropTemps(e) => self.expr(e), ExprKind::Path(ref qpath) => { self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| { let result = mir_to_const(this.lcx, result)?; @@ -490,7 +490,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// leaves the local crate. pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option<bool> { match e.kind { - ExprKind::ConstBlock(e) | ExprKind::DropTemps(e) => self.expr_is_empty(e), + ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.lcx.tcx.hir().body(body).value), ExprKind::DropTemps(e) => self.expr_is_empty(e), ExprKind::Path(ref qpath) => { if !self .typeck_results @@ -810,14 +810,14 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> (ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() { ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)), ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)), - ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))), + ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.to_bits(int.size()))), ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits( int.try_into().expect("invalid f32 bit representation"), ))), ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits( int.try_into().expect("invalid f64 bit representation"), ))), - ty::RawPtr(_, _) => Some(Constant::RawPtr(int.assert_bits(int.size()))), + ty::RawPtr(_, _) => Some(Constant::RawPtr(int.to_bits(int.size()))), _ => None, }, (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => { diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index c649c179468..36634817fc9 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -295,7 +295,7 @@ impl HirEqInterExpr<'_, '_, '_> { self.eq_expr(lx, rx) && self.eq_ty(lt, rt) }, (&ExprKind::Closure(_l), &ExprKind::Closure(_r)) => false, - (&ExprKind::ConstBlock(lb), &ExprKind::ConstBlock(rb)) => self.eq_expr(lb, rb), + (&ExprKind::ConstBlock(lb), &ExprKind::ConstBlock(rb)) => self.eq_body(lb.body, rb.body), (&ExprKind::Continue(li), &ExprKind::Continue(ri)) => { both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name) }, @@ -769,8 +769,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { // closures inherit TypeckResults self.hash_expr(self.cx.tcx.hir().body(body).value); }, - ExprKind::ConstBlock(l_id) => { - self.hash_expr(l_id); + ExprKind::ConstBlock(ref l_id) => { + self.hash_body(l_id.body); }, ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => { self.hash_expr(e); diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index b10830b24e1..2f6bf920967 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -647,7 +647,7 @@ fn item_children_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Vec<Re /// This function is expensive and should be used sparingly. pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Vec<Res> { fn find_crates(tcx: TyCtxt<'_>, name: Symbol) -> impl Iterator<Item = DefId> + '_ { - tcx.crates_including_speculative(()) + tcx.crates(()) .iter() .copied() .filter(move |&num| tcx.crate_name(num) == name) @@ -1534,7 +1534,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti if let rustc_ty::Adt(_, subst) = ty.kind() && let bnd_ty = subst.type_at(0) && let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx) - && let Some(min_const) = mir_to_const(cx, Const::from_ty_const(min_val, cx.tcx)) + && let Some(min_const) = mir_to_const(cx, Const::from_ty_const(min_val, bnd_ty, cx.tcx)) && let Some(start_const) = constant(cx, cx.typeck_results(), start) { start_const == min_const @@ -1547,7 +1547,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti if let rustc_ty::Adt(_, subst) = ty.kind() && let bnd_ty = subst.type_at(0) && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx) - && let Some(max_const) = mir_to_const(cx, Const::from_ty_const(max_val, cx.tcx)) + && let Some(max_const) = mir_to_const(cx, Const::from_ty_const(max_val, bnd_ty, cx.tcx)) && let Some(end_const) = constant(cx, cx.typeck_results(), end) { end_const == max_const diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 3414b5ef680..6e5626297c9 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -23,7 +23,7 @@ use rustc_middle::ty::{ }; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; -use rustc_target::abi::{Size, VariantIdx}; +use rustc_target::abi::VariantIdx; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::{Obligation, ObligationCause}; @@ -750,7 +750,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t let output = bounds .projection_bounds() .find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id())) - .map(|p| p.map_bound(|p| p.term.ty().unwrap())); + .map(|p| p.map_bound(|p| p.term.expect_type())); Some(ExprFnSig::Trait(bound.map_bound(|b| b.args.type_at(0)), output, None)) }, _ => None, @@ -798,7 +798,7 @@ fn sig_from_bounds<'tcx>( // Multiple different fn trait impls. Is this even allowed? return None; } - output = Some(pred.kind().rebind(p.term.ty().unwrap())); + output = Some(pred.kind().rebind(p.term.expect_type())); }, _ => (), } @@ -836,7 +836,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option // Multiple different fn trait impls. Is this even allowed? return None; } - output = pred.kind().rebind(p.term.ty()).transpose(); + output = pred.kind().rebind(p.term.as_type()).transpose(); }, _ => (), } @@ -865,22 +865,8 @@ impl core::ops::Add<u32> for EnumValue { pub fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option<EnumValue> { if let Ok(ConstValue::Scalar(Scalar::Int(value))) = tcx.const_eval_poly(id) { match tcx.type_of(id).instantiate_identity().kind() { - ty::Int(_) => Some(EnumValue::Signed(match value.size().bytes() { - 1 => i128::from(value.assert_bits(Size::from_bytes(1)) as u8 as i8), - 2 => i128::from(value.assert_bits(Size::from_bytes(2)) as u16 as i16), - 4 => i128::from(value.assert_bits(Size::from_bytes(4)) as u32 as i32), - 8 => i128::from(value.assert_bits(Size::from_bytes(8)) as u64 as i64), - 16 => value.assert_bits(Size::from_bytes(16)) as i128, - _ => return None, - })), - ty::Uint(_) => Some(EnumValue::Unsigned(match value.size().bytes() { - 1 => value.assert_bits(Size::from_bytes(1)), - 2 => value.assert_bits(Size::from_bytes(2)), - 4 => value.assert_bits(Size::from_bytes(4)), - 8 => value.assert_bits(Size::from_bytes(8)), - 16 => value.assert_bits(Size::from_bytes(16)), - _ => return None, - })), + ty::Int(_) => Some(EnumValue::Signed(value.to_int(value.size()))), + ty::Uint(_) => Some(EnumValue::Unsigned(value.to_uint(value.size()))), _ => None, } } else { diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr index df14ff396f6..8039c0bfa24 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr @@ -1,35 +1,11 @@ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:188:36 - | -LL | let _ = const { let mut n = 1; n += 1; n }; - | ^^^^^^ - | - = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::arithmetic_side_effects)]` - -error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:191:40 - | -LL | let _ = const { let mut n = 1; n = n + 1; n }; - | ^^^^^ - -error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:194:40 - | -LL | let _ = const { let mut n = 1; n = 1 + n; n }; - | ^^^^^ - -error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:200:59 - | -LL | let _ = const { let mut n = 1; n = -1; n = -(-1); n = -n; n }; - | ^^ - -error: arithmetic operation that can potentially result in unexpected side-effects --> tests/ui/arithmetic_side_effects.rs:304:5 | LL | _n += 1; | ^^^^^^^ + | + = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::arithmetic_side_effects)]` error: arithmetic operation that can potentially result in unexpected side-effects --> tests/ui/arithmetic_side_effects.rs:305:5 @@ -751,5 +727,5 @@ error: arithmetic operation that can potentially result in unexpected side-effec LL | one.sub_assign(1); | ^^^^^^^^^^^^^^^^^ -error: aborting due to 125 previous errors +error: aborting due to 121 previous errors diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed index 84dac431169..05d5b3d10ea 100644 --- a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed +++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed @@ -16,7 +16,7 @@ fn foo( fn skip_on_statements() { #[rustfmt::skip] - { 5+3; } + 5+3; } #[rustfmt::skip] @@ -33,11 +33,11 @@ mod foo { #[clippy::msrv = "1.29"] fn msrv_1_29() { #[cfg_attr(rustfmt, rustfmt::skip)] - { 1+29; } + 1+29; } #[clippy::msrv = "1.30"] fn msrv_1_30() { #[rustfmt::skip] - { 1+30; } + 1+30; } diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs index 4ab5c70e13b..bc29e20210e 100644 --- a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs +++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs @@ -16,7 +16,7 @@ fn foo( fn skip_on_statements() { #[cfg_attr(rustfmt, rustfmt::skip)] - { 5+3; } + 5+3; } #[cfg_attr(rustfmt, rustfmt_skip)] @@ -33,11 +33,11 @@ mod foo { #[clippy::msrv = "1.29"] fn msrv_1_29() { #[cfg_attr(rustfmt, rustfmt::skip)] - { 1+29; } + 1+29; } #[clippy::msrv = "1.30"] fn msrv_1_30() { #[cfg_attr(rustfmt, rustfmt::skip)] - { 1+30; } + 1+30; } diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.fixed b/src/tools/clippy/tests/ui/std_instead_of_core.fixed index ec4ae2ea13c..6ede7bfcd9f 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core.fixed +++ b/src/tools/clippy/tests/ui/std_instead_of_core.fixed @@ -45,8 +45,8 @@ fn std_instead_of_core() { let _ = std::env!("PATH"); - // do not lint until `error_in_core` is stable - use std::error::Error; + use core::error::Error; + //~^ ERROR: used import from `std` instead of `core` // lint items re-exported from private modules, `core::iter::traits::iterator::Iterator` use core::iter::Iterator; diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.rs b/src/tools/clippy/tests/ui/std_instead_of_core.rs index c12c459c7eb..e22b4f61f3e 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core.rs +++ b/src/tools/clippy/tests/ui/std_instead_of_core.rs @@ -45,8 +45,8 @@ fn std_instead_of_core() { let _ = std::env!("PATH"); - // do not lint until `error_in_core` is stable use std::error::Error; + //~^ ERROR: used import from `std` instead of `core` // lint items re-exported from private modules, `core::iter::traits::iterator::Iterator` use std::iter::Iterator; diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.stderr b/src/tools/clippy/tests/ui/std_instead_of_core.stderr index 8f920511cc5..22cb9db7050 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core.stderr +++ b/src/tools/clippy/tests/ui/std_instead_of_core.stderr @@ -50,6 +50,12 @@ LL | let cell_absolute = ::std::cell::Cell::new(8u32); | ^^^ help: consider importing the item from `core`: `core` error: used import from `std` instead of `core` + --> tests/ui/std_instead_of_core.rs:48:9 + | +LL | use std::error::Error; + | ^^^ help: consider importing the item from `core`: `core` + +error: used import from `std` instead of `core` --> tests/ui/std_instead_of_core.rs:52:9 | LL | use std::iter::Iterator; @@ -79,5 +85,5 @@ LL | use alloc::slice::from_ref; = note: `-D clippy::alloc-instead-of-core` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::alloc_instead_of_core)]` -error: aborting due to 12 previous errors +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/unicode.stderr b/src/tools/clippy/tests/ui/unicode.stderr index 9c365e1097d..b004493300e 100644 --- a/src/tools/clippy/tests/ui/unicode.stderr +++ b/src/tools/clippy/tests/ui/unicode.stderr @@ -11,7 +11,7 @@ error: invisible character detected --> tests/ui/unicode.rs:7:12 | LL | print!("Here >< is a SHY, and another"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >\u{AD}< is a SHY, and \u{AD}another"` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >\u{AD}< is a SHY, and \u{AD}another"` error: invisible character detected --> tests/ui/unicode.rs:9:12 diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index a2cdf800a97..a5475a158de 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -94,7 +94,7 @@ pub struct TestProps { // Extra flags to pass to the compiler pub compile_flags: Vec<String>, // Extra flags to pass when the compiled code is run (such as --bench) - pub run_flags: Option<String>, + pub run_flags: Vec<String>, // If present, the name of a file that this test should match when // pretty-printed pub pp_exact: Option<PathBuf>, @@ -107,6 +107,9 @@ pub struct TestProps { // Similar to `aux_builds`, but a list of NAME=somelib.rs of dependencies // to build and pass with the `--extern` flag. pub aux_crates: Vec<(String, String)>, + /// Similar to `aux_builds`, but also passes the resulting dylib path to + /// `-Zcodegen-backend`. + pub aux_codegen_backend: Option<String>, // Environment settings to use for compiling pub rustc_env: Vec<(String, String)>, // Environment variables to unset prior to compiling. @@ -231,6 +234,7 @@ mod directives { pub const AUX_BIN: &'static str = "aux-bin"; pub const AUX_BUILD: &'static str = "aux-build"; pub const AUX_CRATE: &'static str = "aux-crate"; + pub const AUX_CODEGEN_BACKEND: &'static str = "aux-codegen-backend"; pub const EXEC_ENV: &'static str = "exec-env"; pub const RUSTC_ENV: &'static str = "rustc-env"; pub const UNSET_EXEC_ENV: &'static str = "unset-exec-env"; @@ -262,11 +266,12 @@ impl TestProps { error_patterns: vec![], regex_error_patterns: vec![], compile_flags: vec![], - run_flags: None, + run_flags: vec![], pp_exact: None, aux_builds: vec![], aux_bins: vec![], aux_crates: vec![], + aux_codegen_backend: None, revisions: vec![], rustc_env: vec![ ("RUSTC_ICE".to_string(), "0".to_string()), @@ -399,7 +404,9 @@ impl TestProps { config.parse_and_update_revisions(ln, &mut self.revisions); - config.set_name_value_directive(ln, RUN_FLAGS, &mut self.run_flags, |r| r); + if let Some(flags) = config.parse_name_value_directive(ln, RUN_FLAGS) { + self.run_flags.extend(split_flags(&flags)); + } if self.pp_exact.is_none() { self.pp_exact = config.parse_pp_exact(ln, testfile); @@ -444,6 +451,9 @@ impl TestProps { &mut self.aux_crates, Config::parse_aux_crate, ); + if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND) { + self.aux_codegen_backend = Some(r.trim().to_owned()); + } config.push_name_value_directive( ln, EXEC_ENV, @@ -720,6 +730,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "assembly-output", "aux-bin", "aux-build", + "aux-codegen-backend", "aux-crate", "build-aux-docs", "build-fail", @@ -799,6 +810,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-none", "ignore-nto", "ignore-nvptx64", + "ignore-nvptx64-nvidia-cuda", "ignore-openbsd", "ignore-pass", "ignore-remote", @@ -842,9 +854,9 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "needs-asm-support", "needs-dlltool", "needs-dynamic-linking", + "needs-force-clang-based-tests", "needs-git-hash", "needs-llvm-components", - "needs-matching-clang", "needs-profiler-support", "needs-relocation-model-pic", "needs-run-enabled", @@ -1267,6 +1279,8 @@ fn expand_variables(mut value: String, config: &Config) -> String { const CWD: &str = "{{cwd}}"; const SRC_BASE: &str = "{{src-base}}"; const BUILD_BASE: &str = "{{build-base}}"; + const SYSROOT_BASE: &str = "{{sysroot-base}}"; + const TARGET_LINKER: &str = "{{target-linker}}"; if value.contains(CWD) { let cwd = env::current_dir().unwrap(); @@ -1281,6 +1295,14 @@ fn expand_variables(mut value: String, config: &Config) -> String { value = value.replace(BUILD_BASE, &config.build_base.to_string_lossy()); } + if value.contains(SYSROOT_BASE) { + value = value.replace(SYSROOT_BASE, &config.sysroot_base.to_string_lossy()); + } + + if value.contains(TARGET_LINKER) { + value = value.replace(TARGET_LINKER, config.target_linker.as_deref().unwrap_or("")); + } + value } diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs index 7bc7e4b8680..b96832db67b 100644 --- a/src/tools/compiletest/src/header/needs.rs +++ b/src/tools/compiletest/src/header/needs.rs @@ -100,9 +100,9 @@ pub(super) fn handle_needs( ignore_reason: "ignored when profiler support is disabled", }, Need { - name: "needs-matching-clang", + name: "needs-force-clang-based-tests", condition: config.run_clang_based_tests_with.is_some(), - ignore_reason: "ignored when the used clang does not match the built LLVM", + ignore_reason: "ignored when RUSTBUILD_FORCE_CLANG_BASED_TESTS is not set", }, Need { name: "needs-xray", diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 9bd0002a3d9..dbe016b8305 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -15,7 +15,7 @@ use crate::errors::{self, Error, ErrorKind}; use crate::header::TestProps; use crate::json; use crate::read2::{read2_abbreviated, Truncated}; -use crate::util::{add_dylib_path, dylib_env_var, logv, PathBufExt}; +use crate::util::{add_dylib_path, copy_dir_all, dylib_env_var, logv, PathBufExt}; use crate::ColorConfig; use colored::Colorize; use miropt_test_tools::{files_for_miropt_test, MiroptTest, MiroptTestFile}; @@ -1833,6 +1833,16 @@ impl<'test> TestCx<'test> { )); } } + + // Build any `//@ aux-codegen-backend`, and pass the resulting library + // to `-Zcodegen-backend` when compiling the test file. + if let Some(aux_file) = &self.props.aux_codegen_backend { + let aux_type = self.build_auxiliary(of, aux_file, aux_dir, false); + if let Some(lib_name) = get_lib_name(aux_file.trim_end_matches(".rs"), aux_type) { + let lib_path = aux_dir.join(&lib_name); + rustc.arg(format!("-Zcodegen-backend={}", lib_path.display())); + } + } } fn compose_and_run_compiler(&self, mut rustc: Command, input: Option<String>) -> ProcRes { @@ -2254,6 +2264,9 @@ impl<'test> TestCx<'test> { } match output_file { + // If the test's compile flags specify an output path with `-o`, + // avoid a compiler warning about `--out-dir` being ignored. + _ if self.props.compile_flags.iter().any(|flag| flag == "-o") => {} TargetLocation::ThisFile(path) => { rustc.arg("-o").arg(path); } @@ -2355,7 +2368,7 @@ impl<'test> TestCx<'test> { args.push(exe_file.into_os_string()); // Add the arguments in the run_flags directive - args.extend(self.split_maybe_args(&self.props.run_flags)); + args.extend(self.props.run_flags.iter().map(OsString::from)); let prog = args.remove(0); ProcArgs { prog, args } @@ -2469,6 +2482,7 @@ impl<'test> TestCx<'test> { } } + #[track_caller] fn fatal(&self, err: &str) -> ! { self.error(err); error!("fatal error, panic: {:?}", err); @@ -3457,6 +3471,21 @@ impl<'test> TestCx<'test> { let rmake_out_dir = base_dir.join("rmake_out"); create_dir_all(&rmake_out_dir).unwrap(); + // Copy all input files (apart from rmake.rs) to the temporary directory, + // so that the input directory structure from `tests/run-make/<test>` is mirrored + // to the `rmake_out` directory. + for path in walkdir::WalkDir::new(&self.testpaths.file).min_depth(1) { + let path = path.unwrap().path().to_path_buf(); + if path.file_name().is_some_and(|s| s != "rmake.rs") { + let target = rmake_out_dir.join(path.strip_prefix(&self.testpaths.file).unwrap()); + if path.is_dir() { + copy_dir_all(&path, target).unwrap(); + } else { + fs::copy(&path, target).unwrap(); + } + } + } + // HACK: assume stageN-target, we only want stageN. let stage = self.config.stage_id.split('-').next().unwrap(); @@ -3514,21 +3543,13 @@ impl<'test> TestCx<'test> { .arg(&self.testpaths.file.join("rmake.rs")) .env("TARGET", &self.config.target) .env("PYTHON", &self.config.python) - .env("S", &src_root) .env("RUST_BUILD_STAGE", &self.config.stage_id) .env("RUSTC", cwd.join(&self.config.rustc_path)) - .env("TMPDIR", &rmake_out_dir) .env("LD_LIB_PATH_ENVVAR", dylib_env_var()) .env(dylib_env_var(), &host_dylib_env_paths) .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path)) .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path)) - .env("LLVM_COMPONENTS", &self.config.llvm_components) - // We for sure don't want these tests to run in parallel, so make - // sure they don't have access to these vars if we run via `make` - // at the top level - .env_remove("MAKEFLAGS") - .env_remove("MFLAGS") - .env_remove("CARGO_MAKEFLAGS"); + .env("LLVM_COMPONENTS", &self.config.llvm_components); if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() { let mut stage0_sysroot = build_root.clone(); @@ -3558,7 +3579,7 @@ impl<'test> TestCx<'test> { let target_rpath_env_path = env::join_paths(target_rpath_env_path).unwrap(); let mut cmd = Command::new(&recipe_bin); - cmd.current_dir(&self.testpaths.file) + cmd.current_dir(&rmake_out_dir) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .env("LD_LIB_PATH_ENVVAR", dylib_env_var()) @@ -3566,19 +3587,12 @@ impl<'test> TestCx<'test> { .env(dylib_env_var(), &dylib_env_paths) .env("TARGET", &self.config.target) .env("PYTHON", &self.config.python) - .env("S", &src_root) + .env("SOURCE_ROOT", &src_root) .env("RUST_BUILD_STAGE", &self.config.stage_id) .env("RUSTC", cwd.join(&self.config.rustc_path)) - .env("TMPDIR", &rmake_out_dir) .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path)) .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path)) - .env("LLVM_COMPONENTS", &self.config.llvm_components) - // We for sure don't want these tests to run in parallel, so make - // sure they don't have access to these vars if we run via `make` - // at the top level - .env_remove("MAKEFLAGS") - .env_remove("MFLAGS") - .env_remove("CARGO_MAKEFLAGS"); + .env("LLVM_COMPONENTS", &self.config.llvm_components); if let Some(ref rustdoc) = self.config.rustdoc_path { cmd.env("RUSTDOC", cwd.join(rustdoc)); @@ -4173,10 +4187,12 @@ impl<'test> TestCx<'test> { } fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> String { - let rflags = self.props.run_flags.as_ref(); + // Crude heuristic to detect when the output should have JSON-specific + // normalization steps applied. + let rflags = self.props.run_flags.join(" "); let cflags = self.props.compile_flags.join(" "); - let json = rflags - .map_or(false, |s| s.contains("--format json") || s.contains("--format=json")) + let json = rflags.contains("--format json") + || rflags.contains("--format=json") || cflags.contains("--error-format json") || cflags.contains("--error-format pretty-json") || cflags.contains("--error-format=json") diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 09a7f0395cf..ec20bda8c18 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -1,7 +1,7 @@ use crate::common::Config; use std::env; use std::ffi::OsStr; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::process::Command; use tracing::*; @@ -76,3 +76,17 @@ pub fn add_dylib_path(cmd: &mut Command, paths: impl Iterator<Item = impl Into<P let new_paths = paths.map(Into::into).chain(old_paths.into_iter().flatten()); cmd.env(dylib_env_var(), env::join_paths(new_paths).unwrap()); } + +pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> std::io::Result<()> { + std::fs::create_dir_all(&dst)?; + for entry in std::fs::read_dir(src)? { + let entry = entry?; + let ty = entry.file_type()?; + if ty.is_dir() { + copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?; + } else { + std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; + } + } + Ok(()) +} diff --git a/src/tools/jsondoclint/src/item_kind.rs b/src/tools/jsondoclint/src/item_kind.rs index 9bd04e11cb3..525de03bbce 100644 --- a/src/tools/jsondoclint/src/item_kind.rs +++ b/src/tools/jsondoclint/src/item_kind.rs @@ -150,7 +150,7 @@ impl Kind { ItemEnum::Impl(_) => Impl, ItemEnum::TypeAlias(_) => TypeAlias, ItemEnum::OpaqueTy(_) => OpaqueTy, - ItemEnum::Constant(_) => Constant, + ItemEnum::Constant { .. } => Constant, ItemEnum::Static(_) => Static, ItemEnum::Macro(_) => Macro, ItemEnum::ProcMacro(_) => ProcMacro, diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index 904c2b614f3..5e35ce242fe 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -101,7 +101,10 @@ impl<'a> Validator<'a> { ItemEnum::Impl(x) => self.check_impl(x, id), ItemEnum::TypeAlias(x) => self.check_type_alias(x), ItemEnum::OpaqueTy(x) => self.check_opaque_ty(x), - ItemEnum::Constant(x) => self.check_constant(x), + ItemEnum::Constant { type_, const_ } => { + self.check_type(type_); + self.check_constant(const_); + } ItemEnum::Static(x) => self.check_static(x), ItemEnum::ForeignType => {} // nop ItemEnum::Macro(x) => self.check_macro(x), @@ -231,8 +234,8 @@ impl<'a> Validator<'a> { self.check_generics(&x.generics); } - fn check_constant(&mut self, x: &'a Constant) { - self.check_type(&x.type_); + fn check_constant(&mut self, _x: &'a Constant) { + // nop } fn check_static(&mut self, x: &'a Static) { diff --git a/src/tools/libcxx-version/main.cpp b/src/tools/libcxx-version/main.cpp new file mode 100644 index 00000000000..79df7ef457c --- /dev/null +++ b/src/tools/libcxx-version/main.cpp @@ -0,0 +1,26 @@ +// Detecting the standard library version manually using a bunch of shell commands is very +// complicated and fragile across different platforms. This program provides the major version +// of the standard library on any target platform without requiring any messy work. +// +// It's nothing more than specifying the name of the standard library implementation (either libstdc++ or libc++) +// and its major version. + +#include <iostream> + +int main() { + #ifdef _GLIBCXX_RELEASE + std::cout << "libstdc++ version: " << _GLIBCXX_RELEASE << std::endl; + #elif defined(_LIBCPP_VERSION) + // _LIBCPP_VERSION follows "XXYYZZ" format (e.g., 170001 for 17.0.1). + // ref: https://github.com/llvm/llvm-project/blob/f64732195c1030ee2627ff4e4142038e01df1d26/libcxx/include/__config#L51-L54 + // + // Since we use the major version from _GLIBCXX_RELEASE, we need to extract only the first 2 characters of _LIBCPP_VERSION + // to provide the major version for consistency. + std::cout << "libc++ version: " << std::to_string(_LIBCPP_VERSION).substr(0, 2) << std::endl; + #else + std::cerr << "Coudln't recognize the standard library version." << std::endl; + return 1; + #endif + + return 0; +} diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index 092ad46a7ca..9067cbc6032 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -223,7 +223,7 @@ will eventually sync those changes back into this repository. When working on Miri in the rustc tree, here's how you can run tests: ``` -./x.py test miri --stage 0 +./x.py test miri ``` `--bless` will work, too. @@ -231,7 +231,7 @@ When working on Miri in the rustc tree, here's how you can run tests: You can also directly run Miri on a Rust source file: ``` -./x.py run miri --stage 0 --args src/tools/miri/tests/pass/hello.rs +./x.py run miri --stage 1 --args src/tools/miri/tests/pass/hello.rs ``` ## Advanced topic: Syncing with the rustc repo @@ -287,7 +287,22 @@ https. Add the following to your `.gitconfig`: pushInsteadOf = https://github.com/ ``` -## Internal environment variables +## Further environment variables + +The following environment variables are relevant to `./miri`: + +* `MIRI_AUTO_OPS` indicates whether the automatic execution of rustfmt, clippy and toolchain setup + (as controlled by the `./auto-*` files) should be skipped. If it is set to `no`, they are skipped. + This is used to allow automated IDE actions to avoid the auto ops. +* `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during Miri executions. +* `MIRI_TEST_THREADS` (recognized by `./miri test`) sets the number of threads to use for running + tests. By default, the number of cores is used. +* `MIRI_SKIP_UI_CHECKS` (recognized by `./miri test`) disables checking that the `stderr` or + `stdout` files match the actual output. + +Furthermore, the usual environment variables recognized by `cargo miri` also work for `./miri`, e.g. +`MIRI_LIB_SRC`. Note that `MIRIFLAGS` is ignored by `./miri test` as each test controls the flags it +is run with. The following environment variables are *internal* and must not be used by anyone but Miri itself. They are used to communicate between different Miri diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 208a8b9ee61..c437619a76e 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -448,28 +448,19 @@ Some native rustc `-Z` flags are also very relevant for Miri: * `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri enables this per default because it is needed for [Stacked Borrows] and [Tree Borrows]. -Moreover, Miri recognizes some environment variables (unless noted otherwise, these are supported -by all intended entry points, i.e. `cargo miri` and `./miri {test,run}`): - -* `MIRI_AUTO_OPS` indicates whether the automatic execution of rustfmt, clippy and toolchain setup - should be skipped. If it is set to `no`, they are skipped. This is used to allow automated IDE - actions to avoid the auto ops. -* `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during - Miri executions, also [see "Testing the Miri driver" in `CONTRIBUTING.md`][testing-miri]. +Moreover, Miri recognizes some environment variables: + * `MIRIFLAGS` defines extra flags to be passed to Miri. * `MIRI_LIB_SRC` defines the directory where Miri expects the sources of the standard library that it will build and use for interpretation. This directory must point to the `library` subdirectory of a `rust-lang/rust` repository checkout. -* `MIRI_SYSROOT` indicates the sysroot to use. When using `cargo miri`, this skips the automatic +* `MIRI_SYSROOT` indicates the sysroot to use. When using `cargo miri test`/`cargo miri run`, 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_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.) -* `MIRI_SKIP_UI_CHECKS` (recognized by `./miri test`): don't check whether the - `stderr` or `stdout` files match the actual output. + and running no_std programs. This should *not usually be used*; Miri has a heuristic to detect + no-std targets based on the target name. Setting this on a target that does support libstd can + lead to confusing results. [testing-miri]: CONTRIBUTING.md#testing-the-miri-driver diff --git a/src/tools/miri/bench-cargo-miri/big-allocs/Cargo.lock b/src/tools/miri/bench-cargo-miri/big-allocs/Cargo.lock new file mode 100644 index 00000000000..da0db7f47ea --- /dev/null +++ b/src/tools/miri/bench-cargo-miri/big-allocs/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "big-allocs" +version = "0.1.0" diff --git a/src/tools/miri/bench-cargo-miri/big-allocs/Cargo.toml b/src/tools/miri/bench-cargo-miri/big-allocs/Cargo.toml new file mode 100644 index 00000000000..7234c9371cf --- /dev/null +++ b/src/tools/miri/bench-cargo-miri/big-allocs/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "big-allocs" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs b/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs new file mode 100644 index 00000000000..a1c1708cf3b --- /dev/null +++ b/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs @@ -0,0 +1,13 @@ +//! This is a regression test for https://github.com/rust-lang/miri/issues/3637. +//! `Allocation`s are backed by a `Box<[u8]>`, which we create using `alloc_zeroed`, which should +//! make very large allocations cheap. But then we also need to not clone those `Allocation`s, or +//! we end up slow anyway. + +fn main() { + // We can't use too big of an allocation or this code will encounter an allocation failure in + // CI. Since the allocation can't be huge, we need to do a few iterations so that the effect + // we're trying to measure is clearly visible above the interpreter's startup time. + for _ in 0..10 { + drop(Vec::<u8>::with_capacity(512 * 1024 * 1024)); + } +} diff --git a/src/tools/miri/cargo-miri/src/main.rs b/src/tools/miri/cargo-miri/src/main.rs index 9fdd4c3e470..7d9f77f3752 100644 --- a/src/tools/miri/cargo-miri/src/main.rs +++ b/src/tools/miri/cargo-miri/src/main.rs @@ -1,15 +1,14 @@ #![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq, rustc::internal)] -#[macro_use] -mod util; - mod arg; mod phases; mod setup; +mod util; use std::{env, iter}; use crate::phases::*; +use crate::util::show_error; /// Returns `true` if our flags look like they may be for rustdoc, i.e., this is cargo calling us to /// be rustdoc. It's hard to be sure as cargo does not have a RUSTDOC_WRAPPER or an env var that diff --git a/src/tools/miri/cargo-miri/src/util.rs b/src/tools/miri/cargo-miri/src/util.rs index 28a824e54f6..f36cff1f798 100644 --- a/src/tools/miri/cargo-miri/src/util.rs +++ b/src/tools/miri/cargo-miri/src/util.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::env; use std::ffi::OsString; use std::fs::File; @@ -11,14 +12,15 @@ use serde::{Deserialize, Serialize}; pub use crate::arg::*; -pub fn show_error(msg: &impl std::fmt::Display) -> ! { +pub fn show_error_(msg: &impl std::fmt::Display) -> ! { eprintln!("fatal error: {msg}"); std::process::exit(1) } macro_rules! show_error { - ($($tt:tt)*) => { crate::util::show_error(&format_args!($($tt)*)) }; + ($($tt:tt)*) => { crate::util::show_error_(&format_args!($($tt)*)) }; } +pub(crate) use show_error; /// The information to run a crate with the given environment. #[derive(Clone, Serialize, Deserialize)] @@ -232,21 +234,18 @@ pub fn get_cargo_metadata() -> Metadata { } /// Pulls all the crates in this workspace from the cargo metadata. -/// Workspace members are emitted like "miri 0.1.0 (path+file:///path/to/miri)" /// Additionally, somewhere between cargo metadata and TyCtxt, '-' gets replaced with '_' so we /// make that same transformation here. pub fn local_crates(metadata: &Metadata) -> String { assert!(!metadata.workspace_members.is_empty()); - let mut local_crates = String::new(); - for member in &metadata.workspace_members { - let name = member.repr.split(' ').next().unwrap(); - let name = name.replace('-', "_"); - local_crates.push_str(&name); - local_crates.push(','); - } - local_crates.pop(); // Remove the trailing ',' - - local_crates + let package_name_by_id: HashMap<_, _> = + metadata.packages.iter().map(|package| (&package.id, package.name.as_str())).collect(); + metadata + .workspace_members + .iter() + .map(|id| package_name_by_id[id].replace('-', "_")) + .collect::<Vec<_>>() + .join(",") } /// Debug-print a command that is going to be run. diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index f97a611b364..67985f9b7d6 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -148,8 +148,8 @@ case $HOST_TARGET in UNIX="panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname libc-time fs TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname libc-time fs - TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX threadname pthread-sync libc-time - TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX threadname pthread-sync libc-time + TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX threadname pthread-sync available-parallelism libc-time + TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX threadname pthread-sync available-parallelism libc-time TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX TEST_TARGET=wasm32-wasip2 run_tests_minimal empty_main wasm heap_alloc libc-mem TEST_TARGET=wasm32-unknown-unknown run_tests_minimal empty_main wasm diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index aa06a0dbcdc..0f738653b14 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -21e6de7eb64c09102de3f100420a09edc1a2a8d7 +565cadb514d35e7b851540edbc172af0f606014f diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 002e1062061..ae95d28d3eb 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -257,7 +257,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn ptr_from_addr_cast(&self, addr: u64) -> InterpResult<'tcx, Pointer<Option<Provenance>>> { + fn ptr_from_addr_cast(&self, addr: u64) -> InterpResult<'tcx, Pointer> { trace!("Casting {:#x} to a pointer", addr); let ecx = self.eval_context_ref(); @@ -297,10 +297,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Convert a relative (tcx) pointer to a Miri pointer. fn adjust_alloc_root_pointer( &self, - ptr: Pointer<CtfeProvenance>, + ptr: interpret::Pointer<CtfeProvenance>, tag: BorTag, kind: MemoryKind, - ) -> InterpResult<'tcx, Pointer<Provenance>> { + ) -> InterpResult<'tcx, interpret::Pointer<Provenance>> { let ecx = self.eval_context_ref(); let (prov, offset) = ptr.into_parts(); // offset is relative (AllocId provenance) @@ -310,12 +310,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Add offset with the right kind of pointer-overflowing arithmetic. let dl = ecx.data_layout(); let absolute_addr = dl.overflowing_offset(base_addr, offset.bytes()).0; - Ok(Pointer::new(Provenance::Concrete { alloc_id, tag }, Size::from_bytes(absolute_addr))) + Ok(interpret::Pointer::new( + Provenance::Concrete { alloc_id, tag }, + Size::from_bytes(absolute_addr), + )) } /// When a pointer is used for a memory access, this computes where in which allocation the /// access is going. - fn ptr_get_alloc(&self, ptr: Pointer<Provenance>) -> Option<(AllocId, Size)> { + fn ptr_get_alloc(&self, ptr: interpret::Pointer<Provenance>) -> Option<(AllocId, Size)> { let ecx = self.eval_context_ref(); let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance) diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index d748febeed4..829bfa7cd70 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -8,7 +8,6 @@ )] // Some "regular" crates we want to share with rustc -#[macro_use] extern crate tracing; // The rustc crates we need @@ -26,6 +25,8 @@ use std::num::NonZero; use std::path::PathBuf; use std::str::FromStr; +use tracing::debug; + use rustc_data_structures::sync::Lrc; use rustc_driver::Compilation; use rustc_hir::{self as hir, Node}; diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index a55ec427d5f..c9e7e300593 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -281,8 +281,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn retag_ptr_value( &mut self, kind: RetagKind, - val: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + val: &ImmTy<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx>> { let this = self.eval_context_mut(); let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { @@ -294,7 +294,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn retag_place_contents( &mut self, kind: RetagKind, - place: &PlaceTy<'tcx, Provenance>, + place: &PlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; @@ -304,10 +304,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn protect_place( - &mut self, - place: &MPlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { + fn protect_place(&mut self, place: &MPlaceTy<'tcx>) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_mut(); let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { @@ -327,7 +324,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn give_pointer_debug_name( &mut self, - ptr: Pointer<Option<Provenance>>, + ptr: Pointer, nth_parent: u8, name: &str, ) -> InterpResult<'tcx> { diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs index 8270a8c321c..87d9057cb89 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs @@ -149,11 +149,7 @@ impl<'ecx, 'tcx> DiagnosticCxBuilder<'ecx, 'tcx> { DiagnosticCxBuilder { machine, operation } } - pub fn read( - machine: &'ecx MiriMachine<'tcx>, - tag: ProvenanceExtra, - range: AllocRange, - ) -> Self { + pub fn read(machine: &'ecx MiriMachine<'tcx>, tag: ProvenanceExtra, range: AllocRange) -> Self { let operation = Operation::Access(AccessOp { kind: AccessKind::Read, tag, range }); DiagnosticCxBuilder { machine, operation } } 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 2786668695e..603733f9dc0 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -531,7 +531,7 @@ impl Stacks { trace!( "read access with tag {:?}: {:?}, size {}", tag, - Pointer::new(alloc_id, range.start), + interpret::Pointer::new(alloc_id, range.start), range.size.bytes() ); let dcx = DiagnosticCxBuilder::read(machine, tag, range); @@ -552,7 +552,7 @@ impl Stacks { trace!( "write access with tag {:?}: {:?}, size {}", tag, - Pointer::new(alloc_id, range.start), + interpret::Pointer::new(alloc_id, range.start), range.size.bytes() ); let dcx = DiagnosticCxBuilder::write(machine, tag, range); @@ -587,7 +587,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { /// Returns the provenance that should be used henceforth. fn sb_reborrow( &mut self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, size: Size, new_perm: NewPermission, new_tag: BorTag, @@ -692,7 +692,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { new_tag, orig_tag, place.layout.ty, - Pointer::new(alloc_id, base_offset), + interpret::Pointer::new(alloc_id, base_offset), size.bytes() ); @@ -809,10 +809,10 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { fn sb_retag_place( &mut self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, new_perm: NewPermission, info: RetagInfo, // diagnostics info about this retag - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_mut(); let size = this.size_and_align_of_mplace(place)?.map(|(size, _)| size); // FIXME: If we cannot determine the size (because the unsized tail is an `extern type`), @@ -839,10 +839,10 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { /// `kind` indicates what kind of reference is being created. fn sb_retag_reference( &mut self, - val: &ImmTy<'tcx, Provenance>, + val: &ImmTy<'tcx>, new_perm: NewPermission, info: RetagInfo, // diagnostics info about this retag - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, ImmTy<'tcx>> { let this = self.eval_context_mut(); let place = this.ref_to_mplace(val)?; let new_place = this.sb_retag_place(&place, new_perm, info)?; @@ -855,8 +855,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn sb_retag_ptr_value( &mut self, kind: RetagKind, - val: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + val: &ImmTy<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx>> { let this = self.eval_context_mut(); let new_perm = NewPermission::from_ref_ty(val.layout.ty, kind, this); let cause = match kind { @@ -870,7 +870,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn sb_retag_place_contents( &mut self, kind: RetagKind, - place: &PlaceTy<'tcx, Provenance>, + place: &PlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let retag_fields = this.machine.borrow_tracker.as_mut().unwrap().get_mut().retag_fields; @@ -895,7 +895,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[inline(always)] // yes this helps in our benchmarks fn retag_ptr_inplace( &mut self, - place: &PlaceTy<'tcx, Provenance>, + place: &PlaceTy<'tcx>, new_perm: NewPermission, ) -> InterpResult<'tcx> { let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; @@ -909,18 +909,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } impl<'ecx, 'tcx> ValueVisitor<'tcx, MiriMachine<'tcx>> for RetagVisitor<'ecx, 'tcx> { - type V = PlaceTy<'tcx, Provenance>; + type V = PlaceTy<'tcx>; #[inline(always)] fn ecx(&self) -> &MiriInterpCx<'tcx> { self.ecx } - fn visit_box( - &mut self, - box_ty: Ty<'tcx>, - place: &PlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx> { + fn visit_box(&mut self, box_ty: Ty<'tcx>, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> { // Only boxes for the global allocator get any special treatment. if box_ty.is_box_global(*self.ecx.tcx) { // Boxes get a weak protectors, since they may be deallocated. @@ -930,7 +926,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn visit_value(&mut self, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> { // If this place is smaller than a pointer, we know that it can't contain any // pointers we need to retag, so we can stop recursion early. // This optimization is crucial for ZSTs, because they can contain way more fields @@ -984,10 +980,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// call. /// /// This is used to ensure soundness of in-place function argument/return passing. - fn sb_protect_place( - &mut self, - place: &MPlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { + fn sb_protect_place(&mut self, place: &MPlaceTy<'tcx>) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_mut(); // Retag it. With protection! That is the entire point. diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs index 3b6c29b5eb1..f65f49a75dd 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs @@ -2,6 +2,7 @@ use std::ops::Range; use rustc_data_structures::fx::FxHashSet; +use tracing::trace; use crate::borrow_tracker::{ stacked_borrows::{Item, Permission}, 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 e1c06b2bd98..77e003ab8a7 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -56,7 +56,7 @@ impl<'tcx> Tree { "{} with tag {:?}: {:?}, size {}", access_kind, prov, - Pointer::new(alloc_id, range.start), + interpret::Pointer::new(alloc_id, range.start), range.size.bytes(), ); // TODO: for now we bail out on wildcard pointers. Eventually we should @@ -195,7 +195,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Returns the provenance that should be used henceforth. fn tb_reborrow( &mut self, - place: &MPlaceTy<'tcx, Provenance>, // parent tag extracted from here + place: &MPlaceTy<'tcx>, // parent tag extracted from here ptr_size: Size, new_perm: NewPermission, new_tag: BorTag, @@ -258,7 +258,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { new_tag, orig_tag, place.layout.ty, - Pointer::new(alloc_id, base_offset), + interpret::Pointer::new(alloc_id, base_offset), ptr_size.bytes() ); @@ -327,9 +327,9 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn tb_retag_place( &mut self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, new_perm: NewPermission, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_mut(); // Determine the size of the reborrow. @@ -366,9 +366,9 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Retags an individual pointer, returning the retagged version. fn tb_retag_reference( &mut self, - val: &ImmTy<'tcx, Provenance>, + val: &ImmTy<'tcx>, new_perm: NewPermission, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, ImmTy<'tcx>> { let this = self.eval_context_mut(); let place = this.ref_to_mplace(val)?; let new_place = this.tb_retag_place(&place, new_perm)?; @@ -383,8 +383,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn tb_retag_ptr_value( &mut self, kind: RetagKind, - val: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + val: &ImmTy<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx>> { let this = self.eval_context_mut(); let new_perm = match val.layout.ty.kind() { &ty::Ref(_, pointee, mutability) => @@ -402,7 +402,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn tb_retag_place_contents( &mut self, kind: RetagKind, - place: &PlaceTy<'tcx, Provenance>, + place: &PlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let options = this.machine.borrow_tracker.as_mut().unwrap().get_mut(); @@ -423,7 +423,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[inline(always)] // yes this helps in our benchmarks fn retag_ptr_inplace( &mut self, - place: &PlaceTy<'tcx, Provenance>, + place: &PlaceTy<'tcx>, new_perm: Option<NewPermission>, ) -> InterpResult<'tcx> { if let Some(new_perm) = new_perm { @@ -435,7 +435,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } impl<'ecx, 'tcx> ValueVisitor<'tcx, MiriMachine<'tcx>> for RetagVisitor<'ecx, 'tcx> { - type V = PlaceTy<'tcx, Provenance>; + type V = PlaceTy<'tcx>; #[inline(always)] fn ecx(&self) -> &MiriInterpCx<'tcx> { @@ -445,11 +445,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Regardless of how `Unique` is handled, Boxes are always reborrowed. /// When `Unique` is also reborrowed, then it behaves exactly like `Box` /// except for the fact that `Box` has a non-zero-sized reborrow. - fn visit_box( - &mut self, - box_ty: Ty<'tcx>, - place: &PlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx> { + fn visit_box(&mut self, box_ty: Ty<'tcx>, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> { // Only boxes for the global allocator get any special treatment. if box_ty.is_box_global(*self.ecx.tcx) { let new_perm = NewPermission::from_unique_ty( @@ -463,7 +459,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn visit_value(&mut self, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> { // If this place is smaller than a pointer, we know that it can't contain any // pointers we need to retag, so we can stop recursion early. // This optimization is crucial for ZSTs, because they can contain way more fields @@ -526,10 +522,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// call. /// /// This is used to ensure soundness of in-place function argument/return passing. - fn tb_protect_place( - &mut self, - place: &MPlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { + fn tb_protect_place(&mut self, place: &MPlaceTy<'tcx>) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_mut(); // Retag it. With protection! That is the entire point. @@ -581,7 +574,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// of `ptr` (with 0 representing `ptr` itself) fn tb_give_pointer_debug_name( &mut self, - ptr: Pointer<Option<Provenance>>, + ptr: Pointer, nth_parent: u8, name: &str, ) -> InterpResult<'tcx> { @@ -604,8 +597,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// and output can be used by `retag_ptr_inplace`. fn inner_ptr_of_unique<'tcx>( ecx: &MiriInterpCx<'tcx>, - place: &PlaceTy<'tcx, Provenance>, -) -> InterpResult<'tcx, PlaceTy<'tcx, Provenance>> { + place: &PlaceTy<'tcx>, +) -> InterpResult<'tcx, PlaceTy<'tcx>> { // Follows the same layout as `interpret/visitor.rs:walk_value` for `Box` in // `rustc_const_eval`, just with one fewer layer. // Here we have a `Unique(NonNull(*mut), PhantomData)` diff --git a/src/tools/miri/src/clock.rs b/src/tools/miri/src/clock.rs index fd0c121626b..c9bffc449f7 100644 --- a/src/tools/miri/src/clock.rs +++ b/src/tools/miri/src/clock.rs @@ -6,7 +6,7 @@ use std::time::{Duration, Instant as StdInstant}; /// This number is pretty random, but it has been shown to approximately cause /// some sample programs to run within an order of magnitude of real time on desktop CPUs. /// (See `tests/pass/shims/time-with-isolation*.rs`.) -const NANOSECONDS_PER_BASIC_BLOCK: u64 = 5000; +const NANOSECONDS_PER_BASIC_BLOCK: u128 = 5000; #[derive(Debug)] pub struct Instant { @@ -16,19 +16,24 @@ pub struct Instant { #[derive(Debug)] enum InstantKind { Host(StdInstant), - Virtual { nanoseconds: u64 }, + Virtual { nanoseconds: u128 }, } impl Instant { - pub fn checked_add(&self, duration: Duration) -> Option<Instant> { + /// Will try to add `duration`, but if that overflows it may add less. + pub fn add_lossy(&self, duration: Duration) -> Instant { match self.kind { - InstantKind::Host(instant) => - instant.checked_add(duration).map(|i| Instant { kind: InstantKind::Host(i) }), - InstantKind::Virtual { nanoseconds } => - u128::from(nanoseconds) - .checked_add(duration.as_nanos()) - .and_then(|n| u64::try_from(n).ok()) - .map(|nanoseconds| Instant { kind: InstantKind::Virtual { nanoseconds } }), + InstantKind::Host(instant) => { + // If this overflows, try adding just 1h and assume that will not overflow. + let i = instant + .checked_add(duration) + .unwrap_or_else(|| instant.checked_add(Duration::from_secs(3600)).unwrap()); + Instant { kind: InstantKind::Host(i) } + } + InstantKind::Virtual { nanoseconds } => { + let n = nanoseconds.saturating_add(duration.as_nanos()); + Instant { kind: InstantKind::Virtual { nanoseconds: n } } + } } } @@ -39,7 +44,17 @@ impl Instant { ( InstantKind::Virtual { nanoseconds }, InstantKind::Virtual { nanoseconds: earlier }, - ) => Duration::from_nanos(nanoseconds.saturating_sub(earlier)), + ) => { + let duration = nanoseconds.saturating_sub(earlier); + // `Duration` does not provide a nice constructor from a `u128` of nanoseconds, + // so we have to implement this ourselves. + // It is possible for second to overflow because u64::MAX < (u128::MAX / 1e9). + // It will be saturated to u64::MAX seconds if the value after division exceeds u64::MAX. + let seconds = u64::try_from(duration / 1_000_000_000).unwrap_or(u64::MAX); + // It is impossible for nanosecond to overflow because u32::MAX > 1e9. + let nanosecond = u32::try_from(duration.wrapping_rem(1_000_000_000)).unwrap(); + Duration::new(seconds, nanosecond) + } _ => panic!("all `Instant` must be of the same kind"), } } @@ -54,12 +69,13 @@ pub struct Clock { #[derive(Debug)] enum ClockKind { Host { - /// The "time anchor" for this machine's monotone clock. - time_anchor: StdInstant, + /// The "epoch" for this machine's monotone clock: + /// the moment we consider to be time = 0. + epoch: StdInstant, }, Virtual { /// The "current virtual time". - nanoseconds: Cell<u64>, + nanoseconds: Cell<u128>, }, } @@ -67,7 +83,7 @@ impl Clock { /// Create a new clock based on the availability of communication with the host. pub fn new(communicate: bool) -> Self { let kind = if communicate { - ClockKind::Host { time_anchor: StdInstant::now() } + ClockKind::Host { epoch: StdInstant::now() } } else { ClockKind::Virtual { nanoseconds: 0.into() } }; @@ -93,16 +109,19 @@ impl Clock { ClockKind::Host { .. } => std::thread::sleep(duration), ClockKind::Virtual { nanoseconds } => { // Just pretend that we have slept for some time. - let nanos: u64 = duration.as_nanos().try_into().unwrap(); - nanoseconds.update(|x| x + nanos); + let nanos: u128 = duration.as_nanos(); + nanoseconds.update(|x| { + x.checked_add(nanos) + .expect("Miri's virtual clock cannot represent an execution this long") + }); } } } - /// Return the `anchor` instant, to convert between monotone instants and durations relative to the anchor. - pub fn anchor(&self) -> Instant { + /// Return the `epoch` instant (time = 0), to convert between monotone instants and absolute durations. + pub fn epoch(&self) -> Instant { match &self.kind { - ClockKind::Host { time_anchor } => Instant { kind: InstantKind::Host(*time_anchor) }, + ClockKind::Host { epoch } => Instant { kind: InstantKind::Host(*epoch) }, ClockKind::Virtual { .. } => Instant { kind: InstantKind::Virtual { nanoseconds: 0 } }, } } diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 719c262290e..2baa09bec16 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -606,9 +606,9 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// Perform an atomic read operation at the memory location. fn read_scalar_atomic( &self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, atomic: AtomicReadOrd, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); this.atomic_access_check(place, AtomicAccessType::Load(atomic))?; // This will read from the last store in the modification order of this location. In case @@ -625,8 +625,8 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// Perform an atomic write operation at the memory location. fn write_scalar_atomic( &mut self, - val: Scalar<Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + val: Scalar, + dest: &MPlaceTy<'tcx>, atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -645,12 +645,12 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// Perform an atomic RMW operation on a memory location. fn atomic_rmw_op_immediate( &mut self, - place: &MPlaceTy<'tcx, Provenance>, - rhs: &ImmTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, + rhs: &ImmTy<'tcx>, op: mir::BinOp, not: bool, atomic: AtomicRwOrd, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, ImmTy<'tcx>> { let this = self.eval_context_mut(); this.atomic_access_check(place, AtomicAccessType::Rmw)?; @@ -670,10 +670,10 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// scalar value, the old value is returned. fn atomic_exchange_scalar( &mut self, - place: &MPlaceTy<'tcx, Provenance>, - new: Scalar<Provenance>, + place: &MPlaceTy<'tcx>, + new: Scalar, atomic: AtomicRwOrd, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.atomic_access_check(place, AtomicAccessType::Rmw)?; @@ -690,11 +690,11 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// scalar value, the old value is returned. fn atomic_min_max_scalar( &mut self, - place: &MPlaceTy<'tcx, Provenance>, - rhs: ImmTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, + rhs: ImmTy<'tcx>, min: bool, atomic: AtomicRwOrd, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, ImmTy<'tcx>> { let this = self.eval_context_mut(); this.atomic_access_check(place, AtomicAccessType::Rmw)?; @@ -726,9 +726,9 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// identical. fn atomic_compare_exchange_scalar( &mut self, - place: &MPlaceTy<'tcx, Provenance>, - expect_old: &ImmTy<'tcx, Provenance>, - new: Scalar<Provenance>, + place: &MPlaceTy<'tcx>, + expect_old: &ImmTy<'tcx>, + new: Scalar, success: AtomicRwOrd, fail: AtomicReadOrd, can_fail_spuriously: bool, @@ -948,7 +948,7 @@ impl VClockAlloc { mem_clocks: &MemoryCellClocks, access: AccessType, access_size: Size, - ptr_dbg: Pointer<AllocId>, + ptr_dbg: interpret::Pointer<AllocId>, ty: Option<Ty<'_>>, ) -> InterpResult<'tcx> { let (active_index, active_clocks) = global.active_thread_state(thread_mgr); @@ -1063,7 +1063,7 @@ impl VClockAlloc { mem_clocks, AccessType::NaRead(read_type), access_range.size, - Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)), + interpret::Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)), ty, ); } @@ -1108,7 +1108,7 @@ impl VClockAlloc { mem_clocks, AccessType::NaWrite(write_type), access_range.size, - Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)), + interpret::Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)), ty, ); } @@ -1163,7 +1163,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { /// Checks that an atomic access is legal at the given place. fn atomic_access_check( &self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, access_type: AtomicAccessType, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); @@ -1219,7 +1219,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { /// associated memory-place and on the current thread. fn validate_atomic_load( &self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, atomic: AtomicReadOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); @@ -1241,7 +1241,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { /// associated memory-place and on the current thread. fn validate_atomic_store( &mut self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -1263,7 +1263,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { /// at the associated memory place and on the current thread. fn validate_atomic_rmw( &mut self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { use AtomicRwOrd::*; @@ -1292,7 +1292,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { /// Generic atomic operation implementation fn validate_atomic_op<A: Debug + Copy>( &self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, atomic: A, access: AccessType, mut op: impl FnMut( @@ -1337,7 +1337,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { mem_clocks, access, place.layout.size, - Pointer::new( + interpret::Pointer::new( alloc_id, Size::from_bytes(mem_clocks_range.start), ), diff --git a/src/tools/miri/src/concurrency/init_once.rs b/src/tools/miri/src/concurrency/init_once.rs index ed10c128026..9145ef32c52 100644 --- a/src/tools/miri/src/concurrency/init_once.rs +++ b/src/tools/miri/src/concurrency/init_once.rs @@ -7,7 +7,7 @@ use super::sync::EvalContextExtPriv as _; use super::vector_clock::VClock; use crate::*; -declare_id!(InitOnceId); +super::sync::declare_id!(InitOnceId); #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] /// The current status of a one time initialization. @@ -33,10 +33,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { #[inline] fn init_once_get_or_create<F>(&mut self, existing: F) -> InterpResult<'tcx, InitOnceId> where - F: FnOnce( - &mut MiriInterpCx<'tcx>, - InitOnceId, - ) -> InterpResult<'tcx, Option<InitOnceId>>, + F: FnOnce(&mut MiriInterpCx<'tcx>, InitOnceId) -> InterpResult<'tcx, Option<InitOnceId>>, { let this = self.eval_context_mut(); let next_index = this.machine.sync.init_onces.next_index(); @@ -54,7 +51,7 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn init_once_get_or_create_id( &mut self, - lock_op: &OpTy<'tcx, Provenance>, + lock_op: &OpTy<'tcx>, lock_layout: TyAndLayout<'tcx>, offset: u64, ) -> InterpResult<'tcx, InitOnceId> { diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs index 15e1a94d6db..822d173ac06 100644 --- a/src/tools/miri/src/concurrency/mod.rs +++ b/src/tools/miri/src/concurrency/mod.rs @@ -1,8 +1,7 @@ pub mod data_race; +pub mod init_once; mod range_object_map; -#[macro_use] pub mod sync; -pub mod init_once; pub mod thread; mod vector_clock; pub mod weak_memory; diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index 52036f4ed2c..76a045c4dc1 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -1,5 +1,6 @@ use std::collections::{hash_map::Entry, VecDeque}; use std::ops::Not; +use std::time::Duration; use rustc_data_structures::fx::FxHashMap; use rustc_index::{Idx, IndexVec}; @@ -55,12 +56,13 @@ macro_rules! declare_id { } impl $name { - pub fn to_u32_scalar(&self) -> Scalar<Provenance> { + pub fn to_u32_scalar(&self) -> Scalar { Scalar::from_u32(self.0.get()) } } }; } +pub(super) use declare_id; declare_id!(MutexId); @@ -160,16 +162,14 @@ pub struct SynchronizationObjects { // Private extension trait for local helper methods impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExtPriv<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Lazily initialize the ID of this Miri sync structure. /// ('0' indicates uninit.) #[inline] fn get_or_create_id<Id: SyncId>( &mut self, next_id: Id, - lock_op: &OpTy<'tcx, Provenance>, + lock_op: &OpTy<'tcx>, lock_layout: TyAndLayout<'tcx>, offset: u64, ) -> InterpResult<'tcx, Option<Id>> { @@ -244,10 +244,7 @@ pub(super) trait EvalContextExtPriv<'tcx>: #[inline] fn condvar_get_or_create<F>(&mut self, existing: F) -> InterpResult<'tcx, CondvarId> where - F: FnOnce( - &mut MiriInterpCx<'tcx>, - CondvarId, - ) -> InterpResult<'tcx, Option<CondvarId>>, + F: FnOnce(&mut MiriInterpCx<'tcx>, CondvarId) -> InterpResult<'tcx, Option<CondvarId>>, { let this = self.eval_context_mut(); let next_index = this.machine.sync.condvars.next_index(); @@ -266,8 +263,8 @@ pub(super) trait EvalContextExtPriv<'tcx>: fn condvar_reacquire_mutex( &mut self, mutex: MutexId, - retval: Scalar<Provenance>, - dest: MPlaceTy<'tcx, Provenance>, + retval: Scalar, + dest: MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if this.mutex_is_locked(mutex) { @@ -291,7 +288,7 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn mutex_get_or_create_id( &mut self, - lock_op: &OpTy<'tcx, Provenance>, + lock_op: &OpTy<'tcx>, lock_layout: TyAndLayout<'tcx>, offset: u64, ) -> InterpResult<'tcx, MutexId> { @@ -303,7 +300,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn rwlock_get_or_create_id( &mut self, - lock_op: &OpTy<'tcx, Provenance>, + lock_op: &OpTy<'tcx>, lock_layout: TyAndLayout<'tcx>, offset: u64, ) -> InterpResult<'tcx, RwLockId> { @@ -315,7 +312,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn condvar_get_or_create_id( &mut self, - lock_op: &OpTy<'tcx, Provenance>, + lock_op: &OpTy<'tcx>, lock_layout: TyAndLayout<'tcx>, offset: u64, ) -> InterpResult<'tcx, CondvarId> { @@ -397,12 +394,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Put the thread into the queue waiting for the mutex. /// Once the Mutex becomes available, `retval` will be written to `dest`. #[inline] - fn mutex_enqueue_and_block( - &mut self, - id: MutexId, - retval: Scalar<Provenance>, - dest: MPlaceTy<'tcx, Provenance>, - ) { + fn mutex_enqueue_and_block(&mut self, id: MutexId, retval: Scalar, dest: MPlaceTy<'tcx>) { let this = self.eval_context_mut(); assert!(this.mutex_is_locked(id), "queing on unlocked mutex"); let thread = this.active_thread(); @@ -413,8 +405,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { callback!( @capture<'tcx> { id: MutexId, - retval: Scalar<Provenance>, - dest: MPlaceTy<'tcx, Provenance>, + retval: Scalar, + dest: MPlaceTy<'tcx>, } @unblock = |this| { assert!(!this.mutex_is_locked(id)); @@ -510,8 +502,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn rwlock_enqueue_and_block_reader( &mut self, id: RwLockId, - retval: Scalar<Provenance>, - dest: MPlaceTy<'tcx, Provenance>, + retval: Scalar, + dest: MPlaceTy<'tcx>, ) { let this = self.eval_context_mut(); let thread = this.active_thread(); @@ -523,8 +515,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { callback!( @capture<'tcx> { id: RwLockId, - retval: Scalar<Provenance>, - dest: MPlaceTy<'tcx, Provenance>, + retval: Scalar, + dest: MPlaceTy<'tcx>, } @unblock = |this| { this.rwlock_reader_lock(id); @@ -593,8 +585,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn rwlock_enqueue_and_block_writer( &mut self, id: RwLockId, - retval: Scalar<Provenance>, - dest: MPlaceTy<'tcx, Provenance>, + retval: Scalar, + dest: MPlaceTy<'tcx>, ) { let this = self.eval_context_mut(); assert!(this.rwlock_is_locked(id), "write-queueing on unlocked rwlock"); @@ -606,8 +598,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { callback!( @capture<'tcx> { id: RwLockId, - retval: Scalar<Provenance>, - dest: MPlaceTy<'tcx, Provenance>, + retval: Scalar, + dest: MPlaceTy<'tcx>, } @unblock = |this| { this.rwlock_writer_lock(id); @@ -632,10 +624,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, condvar: CondvarId, mutex: MutexId, - timeout: Option<Timeout>, - retval_succ: Scalar<Provenance>, - retval_timeout: Scalar<Provenance>, - dest: MPlaceTy<'tcx, Provenance>, + timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>, + retval_succ: Scalar, + retval_timeout: Scalar, + dest: MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if let Some(old_locked_count) = this.mutex_unlock(mutex)? { @@ -659,9 +651,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { @capture<'tcx> { condvar: CondvarId, mutex: MutexId, - retval_succ: Scalar<Provenance>, - retval_timeout: Scalar<Provenance>, - dest: MPlaceTy<'tcx, Provenance>, + retval_succ: Scalar, + retval_timeout: Scalar, + dest: MPlaceTy<'tcx>, } @unblock = |this| { // The condvar was signaled. Make sure we get the clock for that. @@ -713,11 +705,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, addr: u64, bitset: u32, - timeout: Option<Timeout>, - retval_succ: Scalar<Provenance>, - retval_timeout: Scalar<Provenance>, - dest: MPlaceTy<'tcx, Provenance>, - errno_timeout: Scalar<Provenance>, + timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>, + retval_succ: Scalar, + retval_timeout: Scalar, + dest: MPlaceTy<'tcx>, + errno_timeout: Scalar, ) { let this = self.eval_context_mut(); let thread = this.active_thread(); @@ -731,10 +723,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { callback!( @capture<'tcx> { addr: u64, - retval_succ: Scalar<Provenance>, - retval_timeout: Scalar<Provenance>, - dest: MPlaceTy<'tcx, Provenance>, - errno_timeout: Scalar<Provenance>, + retval_succ: Scalar, + retval_timeout: Scalar, + dest: MPlaceTy<'tcx>, + errno_timeout: Scalar, } @unblock = |this| { let futex = this.machine.sync.futexes.get(&addr).unwrap(); diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 06af72dadbd..6a2b99825ad 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -256,10 +256,10 @@ pub struct Thread<'tcx> { /// which then forwards it to 'Resume'. However this argument is implicit in MIR, /// so we have to store it out-of-band. When there are multiple active unwinds, /// the innermost one is always caught first, so we can store them as a stack. - pub(crate) panic_payloads: Vec<Scalar<Provenance>>, + pub(crate) panic_payloads: Vec<Scalar>, /// Last OS error location in memory. It is a 32-bit integer. - pub(crate) last_error: Option<MPlaceTy<'tcx, Provenance>>, + pub(crate) last_error: Option<MPlaceTy<'tcx>>, } pub type StackEmptyCallback<'tcx> = @@ -407,7 +407,7 @@ impl VisitProvenance for Frame<'_, Provenance, FrameExtra<'_>> { /// The moment in time when a blocked thread should be woken up. #[derive(Debug)] -pub enum Timeout { +enum Timeout { Monotonic(Instant), RealTime(SystemTime), } @@ -421,6 +421,34 @@ impl Timeout { time.duration_since(SystemTime::now()).unwrap_or(Duration::ZERO), } } + + /// Will try to add `duration`, but if that overflows it may add less. + fn add_lossy(&self, duration: Duration) -> Self { + match self { + Timeout::Monotonic(i) => Timeout::Monotonic(i.add_lossy(duration)), + Timeout::RealTime(s) => { + // If this overflows, try adding just 1h and assume that will not overflow. + Timeout::RealTime( + s.checked_add(duration) + .unwrap_or_else(|| s.checked_add(Duration::from_secs(3600)).unwrap()), + ) + } + } + } +} + +/// The clock to use for the timeout you are asking for. +#[derive(Debug, Copy, Clone)] +pub enum TimeoutClock { + Monotonic, + RealTime, +} + +/// Whether the timeout is relative or absolute. +#[derive(Debug, Copy, Clone)] +pub enum TimeoutAnchor { + Relative, + Absolute, } /// A set of threads. @@ -432,9 +460,8 @@ pub struct ThreadManager<'tcx> { /// /// Note that this vector also contains terminated threads. threads: IndexVec<ThreadId, Thread<'tcx>>, - /// A mapping from a thread-local static to an allocation id of a thread - /// specific allocation. - thread_local_alloc_ids: FxHashMap<(DefId, ThreadId), Pointer<Provenance>>, + /// A mapping from a thread-local static to the thread specific allocation. + thread_local_allocs: FxHashMap<(DefId, ThreadId), StrictPointer>, /// A flag that indicates that we should change the active thread. yield_active_thread: bool, } @@ -443,7 +470,7 @@ impl VisitProvenance for ThreadManager<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let ThreadManager { threads, - thread_local_alloc_ids, + thread_local_allocs, active_thread: _, yield_active_thread: _, } = self; @@ -451,7 +478,7 @@ impl VisitProvenance for ThreadManager<'_> { for thread in threads { thread.visit_provenance(visit); } - for ptr in thread_local_alloc_ids.values() { + for ptr in thread_local_allocs.values() { ptr.visit_provenance(visit); } } @@ -465,7 +492,7 @@ impl<'tcx> Default for ThreadManager<'tcx> { Self { active_thread: ThreadId::MAIN_THREAD, threads, - thread_local_alloc_ids: Default::default(), + thread_local_allocs: Default::default(), yield_active_thread: false, } } @@ -487,16 +514,16 @@ impl<'tcx> ThreadManager<'tcx> { /// Check if we have an allocation for the given thread local static for the /// active thread. - fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option<Pointer<Provenance>> { - self.thread_local_alloc_ids.get(&(def_id, self.active_thread)).cloned() + fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option<StrictPointer> { + self.thread_local_allocs.get(&(def_id, self.active_thread)).cloned() } /// Set the pointer for the allocation of the given thread local /// static for the active thread. /// /// Panics if a thread local is initialized twice for the same thread. - fn set_thread_local_alloc(&mut self, def_id: DefId, ptr: Pointer<Provenance>) { - self.thread_local_alloc_ids.try_insert((def_id, self.active_thread), ptr).unwrap(); + fn set_thread_local_alloc(&mut self, def_id: DefId, ptr: StrictPointer) { + self.thread_local_allocs.try_insert((def_id, self.active_thread), ptr).unwrap(); } /// Borrow the stack of the active thread. @@ -848,7 +875,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn get_or_create_thread_local_alloc( &mut self, def_id: DefId, - ) -> InterpResult<'tcx, Pointer<Provenance>> { + ) -> InterpResult<'tcx, StrictPointer> { let this = self.eval_context_mut(); let tcx = this.tcx; if let Some(old_alloc) = this.machine.threads.get_thread_local_alloc_id(def_id) { @@ -864,7 +891,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } let alloc = this.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?; // We make a full copy of this allocation. - let mut alloc = alloc.inner().adjust_from_tcx(&this.tcx, |ptr| this.global_root_pointer(ptr))?; + let mut alloc = + alloc.inner().adjust_from_tcx(&this.tcx, |ptr| this.global_root_pointer(ptr))?; // This allocation will be deallocated when the thread dies, so it is not in read-only memory. alloc.mutability = Mutability::Mut; // Create a fresh allocation with this content. @@ -878,10 +906,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[inline] fn start_regular_thread( &mut self, - thread: Option<MPlaceTy<'tcx, Provenance>>, - start_routine: Pointer<Option<Provenance>>, + thread: Option<MPlaceTy<'tcx>>, + start_routine: Pointer, start_abi: Abi, - func_arg: ImmTy<'tcx, Provenance>, + func_arg: ImmTy<'tcx>, ret_layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); @@ -948,18 +976,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let gone_thread = this.active_thread(); { let mut free_tls_statics = Vec::new(); - this.machine.threads.thread_local_alloc_ids.retain( - |&(_def_id, thread), &mut alloc_id| { - if thread != gone_thread { - // A different thread, keep this static around. - return true; - } - // Delete this static from the map and from memory. - // We cannot free directly here as we cannot use `?` in this context. - free_tls_statics.push(alloc_id); - false - }, - ); + this.machine.threads.thread_local_allocs.retain(|&(_def_id, thread), &mut alloc_id| { + if thread != gone_thread { + // A different thread, keep this static around. + return true; + } + // Delete this static from the map and from memory. + // We cannot free directly here as we cannot use `?` in this context. + free_tls_statics.push(alloc_id); + false + }); // Now free the TLS statics. for ptr in free_tls_statics { match tls_alloc_action { @@ -997,13 +1023,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn block_thread( &mut self, reason: BlockReason, - timeout: Option<Timeout>, + timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>, callback: impl UnblockCallback<'tcx> + 'tcx, ) { let this = self.eval_context_mut(); - if !this.machine.communicate() && matches!(timeout, Some(Timeout::RealTime(..))) { - panic!("cannot have `RealTime` callback with isolation enabled!") - } + let timeout = timeout.map(|(clock, anchor, duration)| { + let anchor = match clock { + TimeoutClock::RealTime => { + assert!( + this.machine.communicate(), + "cannot have `RealTime` timeout with isolation enabled!" + ); + Timeout::RealTime(match anchor { + TimeoutAnchor::Absolute => SystemTime::UNIX_EPOCH, + TimeoutAnchor::Relative => SystemTime::now(), + }) + } + TimeoutClock::Monotonic => + Timeout::Monotonic(match anchor { + TimeoutAnchor::Absolute => this.machine.clock.epoch(), + TimeoutAnchor::Relative => this.machine.clock.now(), + }), + }; + anchor.add_lossy(duration) + }); this.machine.threads.block_thread(reason, timeout, callback); } diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index 7a49f6d3470..e92eaa8f91f 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -148,7 +148,7 @@ struct StoreElement { // FIXME: this means the store must be fully initialized; // we will have to change this if we want to support atomics on // (partially) uninitialized data. - val: Scalar<Provenance>, + val: Scalar, /// Metadata about loads from this store element, /// behind a RefCell to keep load op take &self @@ -197,7 +197,7 @@ impl StoreBufferAlloc { fn get_or_create_store_buffer<'tcx>( &self, range: AllocRange, - init: Scalar<Provenance>, + init: Scalar, ) -> InterpResult<'tcx, Ref<'_, StoreBuffer>> { let access_type = self.store_buffers.borrow().access_type(range); let pos = match access_type { @@ -222,7 +222,7 @@ impl StoreBufferAlloc { fn get_or_create_store_buffer_mut<'tcx>( &mut self, range: AllocRange, - init: Scalar<Provenance>, + init: Scalar, ) -> InterpResult<'tcx, &mut StoreBuffer> { let buffers = self.store_buffers.get_mut(); let access_type = buffers.access_type(range); @@ -244,7 +244,7 @@ impl StoreBufferAlloc { } impl<'tcx> StoreBuffer { - fn new(init: Scalar<Provenance>) -> Self { + fn new(init: Scalar) -> Self { let mut buffer = VecDeque::new(); buffer.reserve(STORE_BUFFER_LIMIT); let mut ret = Self { buffer }; @@ -282,7 +282,7 @@ impl<'tcx> StoreBuffer { is_seqcst: bool, rng: &mut (impl rand::Rng + ?Sized), validate: impl FnOnce() -> InterpResult<'tcx>, - ) -> InterpResult<'tcx, (Scalar<Provenance>, LoadRecency)> { + ) -> InterpResult<'tcx, (Scalar, LoadRecency)> { // Having a live borrow to store_buffer while calling validate_atomic_load is fine // because the race detector doesn't touch store_buffer @@ -307,7 +307,7 @@ impl<'tcx> StoreBuffer { fn buffered_write( &mut self, - val: Scalar<Provenance>, + val: Scalar, global: &DataRaceState, thread_mgr: &ThreadManager<'_>, is_seqcst: bool, @@ -408,7 +408,7 @@ impl<'tcx> StoreBuffer { /// ATOMIC STORE IMPL in the paper (except we don't need the location's vector clock) fn store_impl( &mut self, - val: Scalar<Provenance>, + val: Scalar, index: VectorIdx, thread_clock: &VClock, is_seqcst: bool, @@ -450,12 +450,7 @@ impl StoreElement { /// buffer regardless of subsequent loads by the same thread; if the earliest load of another /// thread doesn't happen before the current one, then no subsequent load by the other thread /// can happen before the current one. - fn load_impl( - &self, - index: VectorIdx, - clocks: &ThreadClockSet, - is_seqcst: bool, - ) -> Scalar<Provenance> { + fn load_impl(&self, index: VectorIdx, clocks: &ThreadClockSet, is_seqcst: bool) -> Scalar { let mut load_info = self.load_info.borrow_mut(); load_info.sc_loaded |= is_seqcst; let _ = load_info.timestamps.try_insert(index, clocks.clock[index]); @@ -467,10 +462,10 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn buffered_atomic_rmw( &mut self, - new_val: Scalar<Provenance>, - place: &MPlaceTy<'tcx, Provenance>, + new_val: Scalar, + place: &MPlaceTy<'tcx>, atomic: AtomicRwOrd, - init: Scalar<Provenance>, + init: Scalar, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr())?; @@ -493,11 +488,11 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn buffered_atomic_read( &self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, atomic: AtomicReadOrd, - latest_in_mo: Scalar<Provenance>, + latest_in_mo: Scalar, validate: impl FnOnce() -> InterpResult<'tcx>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); if let Some(global) = &this.machine.data_race { let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr())?; @@ -534,10 +529,10 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn buffered_atomic_write( &mut self, - val: Scalar<Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + val: Scalar, + dest: &MPlaceTy<'tcx>, atomic: AtomicWriteOrd, - init: Scalar<Provenance>, + init: Scalar, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr())?; @@ -579,9 +574,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// to perform load_impl on the latest store element fn perform_read_on_buffered_latest( &self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, atomic: AtomicReadOrd, - init: Scalar<Provenance>, + init: Scalar, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index d55f21d74ef..14e29aa423d 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -42,7 +42,7 @@ pub enum TerminationInfo { }, DataRace { involves_non_atomic: bool, - ptr: Pointer<AllocId>, + ptr: interpret::Pointer<AllocId>, op1: RacingOp, op2: RacingOp, extra: Option<&'static str>, @@ -128,7 +128,7 @@ pub enum NonHaltingDiagnostic { details: bool, }, WeakMemoryOutdatedLoad { - ptr: Pointer<Option<Provenance>>, + ptr: Pointer, }, } diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 5c3b8f2d2a0..87b53d87ac8 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -126,7 +126,7 @@ fn try_resolve_did(tcx: TyCtxt<'_>, path: &[&str], namespace: Option<Namespace>) // the one in the sysroot and the one locally built by `cargo test`.) // FIXME: can we prefer the one from the sysroot? 'crates: for krate in - tcx.used_crates(()).iter().filter(|&&krate| tcx.crate_name(krate).as_str() == crate_name) + tcx.crates(()).iter().filter(|&&krate| tcx.crate_name(krate).as_str() == crate_name) { let mut cur_item = DefId { krate: *krate, index: CRATE_DEF_INDEX }; // Go over the modules. @@ -255,7 +255,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Evaluates the scalar at the specified path. - fn eval_path(&self, path: &[&str]) -> OpTy<'tcx, Provenance> { + fn eval_path(&self, path: &[&str]) -> OpTy<'tcx> { let this = self.eval_context_ref(); let instance = this.resolve_path(path, Namespace::ValueNS); // We don't give a span -- this isn't actually used directly by the program anyway. @@ -264,7 +264,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }); const_val.into() } - fn eval_path_scalar(&self, path: &[&str]) -> Scalar<Provenance> { + fn eval_path_scalar(&self, path: &[&str]) -> Scalar { let this = self.eval_context_ref(); let val = this.eval_path(path); this.read_scalar(&val) @@ -272,7 +272,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Helper function to get a `libc` constant as a `Scalar`. - fn eval_libc(&self, name: &str) -> Scalar<Provenance> { + fn eval_libc(&self, name: &str) -> Scalar { self.eval_path_scalar(&["libc", name]) } @@ -293,7 +293,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Helper function to get a `windows` constant as a `Scalar`. - fn eval_windows(&self, module: &str, name: &str) -> Scalar<Provenance> { + fn eval_windows(&self, module: &str, name: &str) -> Scalar { self.eval_context_ref().eval_path_scalar(&["std", "sys", "pal", "windows", module, name]) } @@ -374,7 +374,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = if dest.layout().abi.is_signed() { Scalar::from_int(i, dest.layout().size) } else { - Scalar::from_uint(u64::try_from(i.into()).unwrap(), dest.layout().size) + // `unwrap` can only fail here if `i` is negative + Scalar::from_uint(u128::try_from(i.into()).unwrap(), dest.layout().size) }; self.eval_context_mut().write_scalar(val, dest) } @@ -413,12 +414,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Test if this pointer equals 0. - fn ptr_is_null(&self, ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, bool> { + fn ptr_is_null(&self, ptr: Pointer) -> InterpResult<'tcx, bool> { Ok(ptr.addr().bytes() == 0) } /// Generate some random bytes, and write them to `dest`. - fn gen_random(&mut self, ptr: Pointer<Option<Provenance>>, len: u64) -> InterpResult<'tcx> { + fn gen_random(&mut self, ptr: Pointer, len: u64) -> InterpResult<'tcx> { // Some programs pass in a null pointer and a length of 0 // to their platform's random-generation function (e.g. getrandom()) // on Linux. For compatibility with these programs, we don't perform @@ -453,7 +454,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { f: ty::Instance<'tcx>, caller_abi: Abi, args: &[Immediate<Provenance>], - dest: Option<&MPlaceTy<'tcx, Provenance>>, + dest: Option<&MPlaceTy<'tcx>>, stack_pop: StackPopCleanup, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -501,7 +502,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// The range is relative to `place`. fn visit_freeze_sensitive( &self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, size: Size, mut action: impl FnMut(AllocRange, bool) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { @@ -520,8 +521,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let mut cur_addr = start_addr; // Called when we detected an `UnsafeCell` at the given offset and size. // Calls `action` and advances `cur_ptr`. - let mut unsafe_cell_action = |unsafe_cell_ptr: &Pointer<Option<Provenance>>, - unsafe_cell_size: Size| { + let mut unsafe_cell_action = |unsafe_cell_ptr: &Pointer, unsafe_cell_size: Size| { // We assume that we are given the fields in increasing offset order, // and nothing else changes. let unsafe_cell_addr = unsafe_cell_ptr.addr(); @@ -575,7 +575,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// whether we are inside an `UnsafeCell` or not. struct UnsafeCellVisitor<'ecx, 'tcx, F> where - F: FnMut(&MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx>, + F: FnMut(&MPlaceTy<'tcx>) -> InterpResult<'tcx>, { ecx: &'ecx MiriInterpCx<'tcx>, unsafe_cell_action: F, @@ -583,9 +583,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { impl<'ecx, 'tcx, F> ValueVisitor<'tcx, MiriMachine<'tcx>> for UnsafeCellVisitor<'ecx, 'tcx, F> where - F: FnMut(&MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx>, + F: FnMut(&MPlaceTy<'tcx>) -> InterpResult<'tcx>, { - type V = MPlaceTy<'tcx, Provenance>; + type V = MPlaceTy<'tcx>; #[inline(always)] fn ecx(&self) -> &MiriInterpCx<'tcx> { @@ -603,7 +603,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Hook to detect `UnsafeCell`. - fn visit_value(&mut self, v: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn visit_value(&mut self, v: &MPlaceTy<'tcx>) -> InterpResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); let is_unsafe_cell = match v.layout.ty.kind() { ty::Adt(adt, _) => @@ -649,7 +649,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn visit_union( &mut self, - _v: &MPlaceTy<'tcx, Provenance>, + _v: &MPlaceTy<'tcx>, _fields: NonZero<usize>, ) -> InterpResult<'tcx> { bug!("we should have already handled unions in `visit_value`") @@ -720,7 +720,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Get last error variable as a place, lazily allocating thread-local storage for it if /// necessary. - fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { + fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_mut(); if let Some(errno_place) = this.active_thread_ref().last_error.as_ref() { Ok(errno_place.clone()) @@ -735,14 +735,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Sets the last error variable. - fn set_last_error(&mut self, scalar: Scalar<Provenance>) -> InterpResult<'tcx> { + fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let errno_place = this.last_error_place()?; this.write_scalar(scalar, &errno_place) } /// Gets the last error variable. - fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar<Provenance>> { + fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let errno_place = this.last_error_place()?; this.read_scalar(&errno_place) @@ -750,7 +750,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'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: std::io::Error) -> InterpResult<'tcx, Scalar<Provenance>> { + 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") { @@ -779,7 +779,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(clippy::needless_return)] fn try_errnum_to_io_error( &self, - errnum: Scalar<Provenance>, + errnum: Scalar, ) -> InterpResult<'tcx, Option<std::io::ErrorKind>> { let this = self.eval_context_ref(); let target = &this.tcx.sess.target; @@ -836,7 +836,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &self, op: &impl Readable<'tcx, Provenance>, layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_ref(); let ptr = this.read_pointer(op)?; Ok(this.ptr_to_mplace(ptr, layout)) @@ -849,7 +849,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { offset: u64, base_layout: TyAndLayout<'tcx>, value_layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_ref(); let op_place = this.deref_pointer_as(op, base_layout)?; let offset = Size::from_bytes(offset); @@ -866,7 +866,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { offset: u64, base_layout: TyAndLayout<'tcx>, value_layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); let value_place = this.deref_pointer_and_offset(op, offset, base_layout, value_layout)?; this.read_scalar(&value_place) @@ -876,7 +876,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, op: &impl Readable<'tcx, Provenance>, offset: u64, - value: impl Into<Scalar<Provenance>>, + value: impl Into<Scalar>, base_layout: TyAndLayout<'tcx>, value_layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ()> { @@ -888,10 +888,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None` /// if the value in the `timespec` struct is invalid. Some libc functions will return /// `EINVAL` in this case. - fn read_timespec( - &mut self, - tp: &MPlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Option<Duration>> { + fn read_timespec(&mut self, tp: &MPlaceTy<'tcx>) -> InterpResult<'tcx, Option<Duration>> { let this = self.eval_context_mut(); let seconds_place = this.project_field(tp, 0)?; let seconds_scalar = this.read_scalar(&seconds_place)?; @@ -914,10 +911,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Read bytes from a byte slice. - fn read_byte_slice<'a>( - &'a self, - slice: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, &'a [u8]> + fn read_byte_slice<'a>(&'a self, slice: &ImmTy<'tcx>) -> InterpResult<'tcx, &'a [u8]> where 'tcx: 'a, { @@ -930,7 +924,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Read a sequence of bytes until the first null terminator. - fn read_c_str<'a>(&'a self, ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, &'a [u8]> + fn read_c_str<'a>(&'a self, ptr: Pointer) -> InterpResult<'tcx, &'a [u8]> where 'tcx: 'a, { @@ -963,7 +957,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_c_str( &mut self, c_str: &[u8], - ptr: Pointer<Option<Provenance>>, + ptr: Pointer, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null @@ -982,7 +976,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// until the first null terminator. fn read_c_str_with_char_size<T>( &self, - mut ptr: Pointer<Option<Provenance>>, + mut ptr: Pointer, size: Size, align: Align, ) -> InterpResult<'tcx, Vec<T>> @@ -1014,7 +1008,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Read a sequence of u16 until the first null terminator. - fn read_wide_str(&self, ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, Vec<u16>> { + fn read_wide_str(&self, ptr: Pointer) -> InterpResult<'tcx, Vec<u16>> { self.read_c_str_with_char_size(ptr, Size::from_bytes(2), Align::from_bytes(2).unwrap()) } @@ -1027,7 +1021,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_wide_str( &mut self, wide_str: &[u16], - ptr: Pointer<Option<Provenance>>, + ptr: Pointer, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required @@ -1052,7 +1046,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Read a sequence of wchar_t until the first null terminator. /// Always returns a `Vec<u32>` no matter the size of `wchar_t`. - fn read_wchar_t_str(&self, ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, Vec<u32>> { + fn read_wchar_t_str(&self, ptr: Pointer) -> InterpResult<'tcx, Vec<u32>> { 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) @@ -1138,17 +1132,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { abi: Abi, exp_abi: Abi, link_name: Symbol, - args: &'a [OpTy<'tcx, Provenance>], - ) -> InterpResult<'tcx, &'a [OpTy<'tcx, Provenance>; N]> + args: &'a [OpTy<'tcx>], + ) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> where - &'a [OpTy<'tcx, Provenance>; N]: TryFrom<&'a [OpTy<'tcx, Provenance>]>, + &'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>, { self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?; check_arg_count(args) } /// Mark a machine allocation that was just created as immutable. - fn mark_immutable(&mut self, mplace: &MPlaceTy<'tcx, Provenance>) { + fn mark_immutable(&mut self, mplace: &MPlaceTy<'tcx>) { let this = self.eval_context_mut(); // This got just allocated, so there definitely is a pointer here. let provenance = mplace.ptr().into_pointer_or_addr().unwrap().provenance; @@ -1168,10 +1162,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Returns `None` if `f` is NaN or out of range. fn float_to_int_checked( &self, - src: &ImmTy<'tcx, Provenance>, + src: &ImmTy<'tcx>, cast_to: TyAndLayout<'tcx>, round: rustc_apfloat::Round, - ) -> InterpResult<'tcx, Option<ImmTy<'tcx, Provenance>>> { + ) -> InterpResult<'tcx, Option<ImmTy<'tcx>>> { let this = self.eval_context_ref(); fn float_to_int_inner<'tcx, F: rustc_apfloat::Float>( @@ -1179,7 +1173,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { src: F, cast_to: TyAndLayout<'tcx>, round: rustc_apfloat::Round, - ) -> (Scalar<Provenance>, rustc_apfloat::Status) { + ) -> (Scalar, rustc_apfloat::Status) { let int_size = cast_to.layout.size; match cast_to.ty.kind() { // Unsigned @@ -1267,10 +1261,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Lookup an array of immediates stored as a linker section of name `name`. - fn lookup_link_section( - &mut self, - name: &str, - ) -> InterpResult<'tcx, Vec<ImmTy<'tcx, Provenance>>> { + fn lookup_link_section(&mut self, name: &str) -> InterpResult<'tcx, Vec<ImmTy<'tcx>>> { let this = self.eval_context_mut(); let tcx = this.tcx.tcx; @@ -1338,10 +1329,10 @@ impl<'tcx> MiriMachine<'tcx> { /// Check that the number of args is what we expect. pub fn check_arg_count<'a, 'tcx, const N: usize>( - args: &'a [OpTy<'tcx, Provenance>], -) -> InterpResult<'tcx, &'a [OpTy<'tcx, Provenance>; N]> + args: &'a [OpTy<'tcx>], +) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> where - &'a [OpTy<'tcx, Provenance>; N]: TryFrom<&'a [OpTy<'tcx, Provenance>]>, + &'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>, { if let Ok(ops) = args.try_into() { return Ok(ops); @@ -1364,7 +1355,7 @@ pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec<CrateNum> { .map(|crates| crates.split(',').map(|krate| krate.to_string()).collect::<Vec<_>>()) .unwrap_or_default(); let mut local_crates = Vec::new(); - for &crate_num in tcx.crates_including_speculative(()) { + for &crate_num in tcx.crates(()) { let name = tcx.crate_name(crate_num); let name = name.as_str(); if local_crate_names.iter().any(|local_name| local_name == name) { @@ -1374,7 +1365,7 @@ pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec<CrateNum> { local_crates } -pub(crate) fn bool_to_simd_element(b: bool, size: Size) -> Scalar<Provenance> { +pub(crate) fn bool_to_simd_element(b: bool, size: Size) -> Scalar { // SIMD uses all-1 as pattern for "true". In two's complement, // -1 has all its bits set to one and `from_int` will truncate or // sign-extend it to `size` as required. @@ -1382,7 +1373,7 @@ pub(crate) fn bool_to_simd_element(b: bool, size: Size) -> Scalar<Provenance> { Scalar::from_int(val, size) } -pub(crate) fn simd_element_to_bool(elem: ImmTy<'_, Provenance>) -> InterpResult<'_, bool> { +pub(crate) fn simd_element_to_bool(elem: ImmTy<'_>) -> InterpResult<'_, bool> { let val = elem.to_scalar().to_int(elem.layout.size)?; Ok(match val { 0 => false, diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs index 17f95df9aa1..d76f622e84b 100644 --- a/src/tools/miri/src/intrinsics/atomic.rs +++ b/src/tools/miri/src/intrinsics/atomic.rs @@ -18,8 +18,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_atomic_intrinsic( &mut self, intrinsic_name: &str, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); @@ -124,8 +124,8 @@ impl<'tcx> EvalContextPrivExt<'tcx> for MiriInterpCx<'tcx> {} trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { fn atomic_load( &mut self, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, atomic: AtomicReadOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -140,11 +140,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { Ok(()) } - fn atomic_store( - &mut self, - args: &[OpTy<'tcx, Provenance>], - atomic: AtomicWriteOrd, - ) -> InterpResult<'tcx> { + fn atomic_store(&mut self, args: &[OpTy<'tcx>], atomic: AtomicWriteOrd) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let [place, val] = check_arg_count(args)?; @@ -159,7 +155,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { fn compiler_fence_intrinsic( &mut self, - args: &[OpTy<'tcx, Provenance>], + args: &[OpTy<'tcx>], atomic: AtomicFenceOrd, ) -> InterpResult<'tcx> { let [] = check_arg_count(args)?; @@ -170,7 +166,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { fn atomic_fence_intrinsic( &mut self, - args: &[OpTy<'tcx, Provenance>], + args: &[OpTy<'tcx>], atomic: AtomicFenceOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -181,8 +177,8 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { fn atomic_rmw_op( &mut self, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, atomic_op: AtomicOp, atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { @@ -223,8 +219,8 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { fn atomic_exchange( &mut self, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -240,8 +236,8 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { fn atomic_compare_exchange_impl( &mut self, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, success: AtomicRwOrd, fail: AtomicReadOrd, can_fail_spuriously: bool, @@ -269,8 +265,8 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { fn atomic_compare_exchange( &mut self, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, success: AtomicRwOrd, fail: AtomicReadOrd, ) -> InterpResult<'tcx> { @@ -279,8 +275,8 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { fn atomic_compare_exchange_weak( &mut self, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, success: AtomicRwOrd, fail: AtomicReadOrd, ) -> InterpResult<'tcx> { diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index e39b78d3816..74e39ffd933 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -1,3 +1,5 @@ +#![warn(clippy::arithmetic_side_effects)] + mod atomic; mod simd; @@ -23,8 +25,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> { @@ -79,8 +81,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, intrinsic_name: &str, generic_args: ty::GenericArgsRef<'tcx>, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ret: Option<mir::BasicBlock>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); @@ -385,7 +387,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "frem_fast" => mir::BinOp::Rem, _ => bug!(), }; - let float_finite = |x: &ImmTy<'tcx, _>| -> InterpResult<'tcx, bool> { + let float_finite = |x: &ImmTy<'tcx>| -> InterpResult<'tcx, bool> { let ty::Float(fty) = x.layout.ty.kind() else { bug!("float_finite: non-float input type {}", x.layout.ty) }; diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index ed0c30e2a11..c3b34f0c0c6 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -23,8 +23,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, intrinsic_name: &str, generic_args: ty::GenericArgsRef<'tcx>, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); match intrinsic_name { @@ -452,28 +452,54 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let (no, no_len) = this.operand_to_simd(no)?; let (dest, dest_len) = this.mplace_to_simd(dest)?; let bitmask_len = dest_len.next_multiple_of(8); + if bitmask_len > 64 { + throw_unsup_format!( + "simd_select_bitmask: vectors larger than 64 elements are currently not supported" + ); + } - // The mask must be an integer or an array. - assert!( - mask.layout.ty.is_integral() - || matches!(mask.layout.ty.kind(), ty::Array(elemty, _) if elemty == &this.tcx.types.u8) - ); - assert!(bitmask_len <= 64); - assert_eq!(bitmask_len, mask.layout.size.bits()); assert_eq!(dest_len, yes_len); assert_eq!(dest_len, no_len); - let dest_len = u32::try_from(dest_len).unwrap(); - let bitmask_len = u32::try_from(bitmask_len).unwrap(); - // To read the mask, we transmute it to an integer. - // That does the right thing wrt endianness. - let mask_ty = this.machine.layouts.uint(mask.layout.size).unwrap(); - let mask = mask.transmute(mask_ty, this)?; - let mask: u64 = this.read_scalar(&mask)?.to_bits(mask_ty.size)?.try_into().unwrap(); + // Read the mask, either as an integer or as an array. + let mask: u64 = match mask.layout.ty.kind() { + ty::Uint(_) => { + // Any larger integer type is fine. + assert!(mask.layout.size.bits() >= bitmask_len); + this.read_scalar(mask)?.to_bits(mask.layout.size)?.try_into().unwrap() + } + ty::Array(elem, _len) if elem == &this.tcx.types.u8 => { + // The array must have exactly the right size. + assert_eq!(mask.layout.size.bits(), bitmask_len); + // Read the raw bytes. + let mask = mask.assert_mem_place(); // arrays cannot be immediate + let mask_bytes = + this.read_bytes_ptr_strip_provenance(mask.ptr(), mask.layout.size)?; + // Turn them into a `u64` in the right way. + let mask_size = mask.layout.size.bytes_usize(); + let mut mask_arr = [0u8; 8]; + match this.data_layout().endian { + Endian::Little => { + // Fill the first N bytes. + mask_arr[..mask_size].copy_from_slice(mask_bytes); + u64::from_le_bytes(mask_arr) + } + Endian::Big => { + // Fill the last N bytes. + let i = mask_arr.len().strict_sub(mask_size); + mask_arr[i..].copy_from_slice(mask_bytes); + u64::from_be_bytes(mask_arr) + } + } + } + _ => bug!("simd_select_bitmask: invalid mask type {}", mask.layout.ty), + }; + let dest_len = u32::try_from(dest_len).unwrap(); + let bitmask_len = u32::try_from(bitmask_len).unwrap(); for i in 0..dest_len { let bit_i = simd_bitmask_index(i, dest_len, this.data_layout().endian); - let mask = mask & 1u64.checked_shl(bit_i).unwrap(); + let mask = mask & 1u64.strict_shl(bit_i); let yes = this.read_immediate(&this.project_index(&yes, i.into())?)?; let no = this.read_immediate(&this.project_index(&no, i.into())?)?; let dest = this.project_index(&dest, i.into())?; @@ -485,7 +511,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // If the mask is "padded", ensure that padding is all-zero. // This deliberately does not use `simd_bitmask_index`; these bits are outside // the bitmask. It does not matter in which order we check them. - let mask = mask & 1u64.checked_shl(i).unwrap(); + let mask = mask & 1u64.strict_shl(i); if mask != 0 { throw_ub_format!( "a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits" @@ -498,30 +524,49 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let bitmask_len = op_len.next_multiple_of(8); + if bitmask_len > 64 { + throw_unsup_format!( + "simd_bitmask: vectors larger than 64 elements are currently not supported" + ); + } - // Returns either an unsigned integer or array of `u8`. - assert!( - dest.layout.ty.is_integral() - || matches!(dest.layout.ty.kind(), ty::Array(elemty, _) if elemty == &this.tcx.types.u8) - ); - assert!(bitmask_len <= 64); - assert_eq!(bitmask_len, dest.layout.size.bits()); let op_len = u32::try_from(op_len).unwrap(); - let mut res = 0u64; for i in 0..op_len { let op = this.read_immediate(&this.project_index(&op, i.into())?)?; if simd_element_to_bool(op)? { - res |= 1u64 - .checked_shl(simd_bitmask_index(i, op_len, this.data_layout().endian)) - .unwrap(); + let bit_i = simd_bitmask_index(i, op_len, this.data_layout().endian); + res |= 1u64.strict_shl(bit_i); + } + } + // Write the result, depending on the `dest` type. + // Returns either an unsigned integer or array of `u8`. + match dest.layout.ty.kind() { + ty::Uint(_) => { + // Any larger integer type is fine, it will be zero-extended. + assert!(dest.layout.size.bits() >= bitmask_len); + this.write_int(res, dest)?; + } + ty::Array(elem, _len) if elem == &this.tcx.types.u8 => { + // The array must have exactly the right size. + assert_eq!(dest.layout.size.bits(), bitmask_len); + // We have to write the result byte-for-byte. + let res_size = dest.layout.size.bytes_usize(); + let res_bytes; + let res_bytes_slice = match this.data_layout().endian { + Endian::Little => { + res_bytes = res.to_le_bytes(); + &res_bytes[..res_size] // take the first N bytes + } + Endian::Big => { + res_bytes = res.to_be_bytes(); + &res_bytes[res_bytes.len().strict_sub(res_size)..] // take the last N bytes + } + }; + this.write_bytes_ptr(dest.ptr(), res_bytes_slice.iter().cloned())?; } + _ => bug!("simd_bitmask: invalid return type {}", dest.layout.ty), } - // We have to change the type of the place to be able to write `res` into it. This - // transmutes the integer to an array, which does the right thing wrt endianness. - let dest = - dest.transmute(this.machine.layouts.uint(dest.layout.size).unwrap(), this)?; - this.write_int(res, &dest)?; } "cast" | "as" | "cast_ptr" | "expose_provenance" | "with_exposed_provenance" => { let [op] = check_arg_count(args)?; @@ -590,6 +635,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .expect_const() .eval(*this.tcx, this.param_env(), this.tcx.span) .unwrap() + .1 .unwrap_branch(); let index_len = index.len(); @@ -599,15 +645,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { for i in 0..dest_len { let src_index: u64 = index[usize::try_from(i).unwrap()] .unwrap_leaf() - .try_to_u32() - .unwrap() + .to_u32() .into(); let dest = this.project_index(&dest, i)?; let val = if src_index < left_len { this.read_immediate(&this.project_index(&left, src_index)?)? - } else if src_index < left_len.checked_add(right_len).unwrap() { - let right_idx = src_index.checked_sub(left_len).unwrap(); + } else if src_index < left_len.strict_add(right_len) { + let right_idx = src_index.strict_sub(left_len); this.read_immediate(&this.project_index(&right, right_idx)?)? } else { throw_ub_format!( @@ -646,8 +691,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = if src_index < left_len { this.read_immediate(&this.project_index(&left, src_index)?)? - } else if src_index < left_len.checked_add(right_len).unwrap() { - let right_idx = src_index.checked_sub(left_len).unwrap(); + } else if src_index < left_len.strict_add(right_len) { + let right_idx = src_index.strict_sub(left_len); this.read_immediate(&this.project_index(&right, right_idx)?)? } else { throw_ub_format!( @@ -760,9 +805,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn fminmax_op( &self, op: MinMax, - left: &ImmTy<'tcx, Provenance>, - right: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + left: &ImmTy<'tcx>, + right: &ImmTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); assert_eq!(left.layout.ty, right.layout.ty); let ty::Float(float_ty) = left.layout.ty.kind() else { diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 2fa88b6a246..11cbbde06aa 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -53,7 +53,6 @@ // Some "regular" crates we want to share with rustc extern crate either; -#[macro_use] extern crate tracing; // The rustc crates we need @@ -64,7 +63,6 @@ extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_index; -#[macro_use] extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; @@ -91,13 +89,24 @@ mod range_map; mod shims; // Establish a "crate-wide prelude": we often import `crate::*`. +use rustc_middle::{bug, span_bug}; +use tracing::{info, trace}; // Make all those symbols available in the same place as our own. #[doc(no_inline)] pub use rustc_const_eval::interpret::*; // Resolve ambiguity. #[doc(no_inline)] -pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy, Provenance as _}; +pub use rustc_const_eval::interpret::{self, AllocMap, Provenance as _}; + +// Type aliases that set the provenance parameter. +pub type Pointer = interpret::Pointer<Option<machine::Provenance>>; +pub type StrictPointer = interpret::Pointer<machine::Provenance>; +pub type Scalar = interpret::Scalar<machine::Provenance>; +pub type ImmTy<'tcx> = interpret::ImmTy<'tcx, machine::Provenance>; +pub type OpTy<'tcx> = interpret::OpTy<'tcx, machine::Provenance>; +pub type PlaceTy<'tcx> = interpret::PlaceTy<'tcx, machine::Provenance>; +pub type MPlaceTy<'tcx> = interpret::MPlaceTy<'tcx, machine::Provenance>; pub use crate::intrinsics::EvalContextExt as _; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; @@ -123,8 +132,8 @@ pub use crate::concurrency::{ init_once::{EvalContextExt as _, InitOnceId}, sync::{CondvarId, EvalContextExt as _, MutexId, RwLockId, SynchronizationObjects}, thread::{ - BlockReason, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager, Timeout, - UnblockCallback, + BlockReason, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager, + TimeoutAnchor, TimeoutClock, UnblockCallback, }, }; pub use crate::diagnostics::{ diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index c9b390eb67e..0d91279f9f4 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -240,12 +240,12 @@ pub enum ProvenanceExtra { } #[cfg(target_pointer_width = "64")] -static_assert_size!(Pointer<Provenance>, 24); +static_assert_size!(StrictPointer, 24); // FIXME: this would with in 24bytes but layout optimizations are not smart enough // #[cfg(target_pointer_width = "64")] -//static_assert_size!(Pointer<Option<Provenance>>, 24); +//static_assert_size!(Pointer, 24); #[cfg(target_pointer_width = "64")] -static_assert_size!(Scalar<Provenance>, 32); +static_assert_size!(Scalar, 32); impl fmt::Debug for Provenance { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -269,7 +269,7 @@ impl fmt::Debug for Provenance { } impl interpret::Provenance for Provenance { - /// We use absolute addresses in the `offset` of a `Pointer<Provenance>`. + /// We use absolute addresses in the `offset` of a `StrictPointer`. const OFFSET_IS_ADDR: bool = true; fn get_alloc_id(self) -> Option<AllocId> { @@ -279,7 +279,7 @@ impl interpret::Provenance for Provenance { } } - fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt(ptr: &interpret::Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (prov, addr) = ptr.into_parts(); // address is absolute write!(f, "{:#x}", addr.bytes())?; if f.alternate() { @@ -441,14 +441,14 @@ pub struct MiriMachine<'tcx> { pub(crate) env_vars: EnvVars<'tcx>, /// Return place of the main function. - pub(crate) main_fn_ret_place: Option<MPlaceTy<'tcx, Provenance>>, + pub(crate) main_fn_ret_place: Option<MPlaceTy<'tcx>>, /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. /// We also need the full command line as one string because of Windows. - pub(crate) argc: Option<Pointer<Option<Provenance>>>, - pub(crate) argv: Option<Pointer<Option<Provenance>>>, - pub(crate) cmd_line: Option<Pointer<Option<Provenance>>>, + pub(crate) argc: Option<Pointer>, + pub(crate) argv: Option<Pointer>, + pub(crate) cmd_line: Option<Pointer>, /// TLS state. pub(crate) tls: TlsData<'tcx>, @@ -503,7 +503,7 @@ pub struct MiriMachine<'tcx> { pub(crate) local_crates: Vec<CrateNum>, /// Mapping extern static names to their pointer. - extern_statics: FxHashMap<Symbol, Pointer<Provenance>>, + extern_statics: FxHashMap<Symbol, StrictPointer>, /// The random number generator used for resolving non-determinism. /// Needs to be queried by ptr_to_int, hence needs interior mutability. @@ -564,7 +564,7 @@ pub struct MiriMachine<'tcx> { /// Maps MIR consts to their evaluated result. We combine the const with a "salt" (`usize`) /// that is fixed per stack frame; this lets us have sometimes different results for the /// same const while ensuring consistent results within a single call. - const_cache: RefCell<FxHashMap<(mir::Const<'tcx>, usize), OpTy<'tcx, Provenance>>>, + const_cache: RefCell<FxHashMap<(mir::Const<'tcx>, usize), OpTy<'tcx>>>, /// For each allocation, an offset inside that allocation that was deemed aligned even for /// symbolic alignment checks. This cannot be stored in `AllocExtra` since it needs to be @@ -715,11 +715,7 @@ impl<'tcx> MiriMachine<'tcx> { Ok(()) } - pub(crate) fn add_extern_static( - this: &mut MiriInterpCx<'tcx>, - name: &str, - ptr: Pointer<Option<Provenance>>, - ) { + pub(crate) fn add_extern_static(this: &mut MiriInterpCx<'tcx>, name: &str, ptr: Pointer) { // This got just allocated, so there definitely is a pointer here. let ptr = ptr.into_pointer_or_addr().unwrap(); this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap(); @@ -945,7 +941,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { instance: ty::Instance<'tcx>, abi: Abi, args: &[FnArg<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx>, ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> { @@ -972,7 +968,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn_val: DynSym, abi: Abi, args: &[FnArg<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx>, ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { @@ -984,8 +980,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn call_intrinsic( ecx: &mut MiriInterpCx<'tcx>, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> { @@ -1026,9 +1022,9 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn binary_ptr_op( ecx: &MiriInterpCx<'tcx>, bin_op: mir::BinOp, - left: &ImmTy<'tcx, Provenance>, - right: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + left: &ImmTy<'tcx>, + right: &ImmTy<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx>> { ecx.binary_ptr_op(bin_op, left, right) } @@ -1046,14 +1042,14 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn thread_local_static_pointer( ecx: &mut MiriInterpCx<'tcx>, def_id: DefId, - ) -> InterpResult<'tcx, Pointer<Provenance>> { + ) -> InterpResult<'tcx, StrictPointer> { ecx.get_or_create_thread_local_alloc(def_id) } fn extern_static_pointer( ecx: &MiriInterpCx<'tcx>, def_id: DefId, - ) -> InterpResult<'tcx, Pointer<Provenance>> { + ) -> InterpResult<'tcx, StrictPointer> { let link_name = ecx.item_link_name(def_id); if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) { // Various parts of the engine rely on `get_alloc_info` for size and alignment @@ -1134,9 +1130,9 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn adjust_alloc_root_pointer( ecx: &MiriInterpCx<'tcx>, - ptr: Pointer<CtfeProvenance>, + ptr: interpret::Pointer<CtfeProvenance>, kind: Option<MemoryKind>, - ) -> InterpResult<'tcx, Pointer<Provenance>> { + ) -> InterpResult<'tcx, interpret::Pointer<Provenance>> { let kind = kind.expect("we set our GLOBAL_KIND so this cannot be None"); let alloc_id = ptr.provenance.alloc_id(); if cfg!(debug_assertions) { @@ -1163,20 +1159,14 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { /// Called on `usize as ptr` casts. #[inline(always)] - fn ptr_from_addr_cast( - ecx: &MiriInterpCx<'tcx>, - addr: u64, - ) -> InterpResult<'tcx, Pointer<Option<Self::Provenance>>> { + fn ptr_from_addr_cast(ecx: &MiriInterpCx<'tcx>, addr: u64) -> InterpResult<'tcx, Pointer> { ecx.ptr_from_addr_cast(addr) } /// Called on `ptr as usize` casts. /// (Actually computing the resulting `usize` doesn't need machine help, /// that's just `Scalar::try_to_int`.) - fn expose_ptr( - ecx: &mut InterpCx<'tcx, Self>, - ptr: Pointer<Self::Provenance>, - ) -> InterpResult<'tcx> { + fn expose_ptr(ecx: &mut InterpCx<'tcx, Self>, ptr: StrictPointer) -> InterpResult<'tcx> { match ptr.provenance { Provenance::Concrete { alloc_id, tag } => ecx.expose_ptr(alloc_id, tag), Provenance::Wildcard => { @@ -1197,7 +1187,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { /// stored in machine state). fn ptr_get_alloc( ecx: &MiriInterpCx<'tcx>, - ptr: Pointer<Self::Provenance>, + ptr: StrictPointer, ) -> Option<(AllocId, Size, Self::ProvenanceExtra)> { let rel = ecx.ptr_get_alloc(ptr); @@ -1295,8 +1285,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn retag_ptr_value( ecx: &mut InterpCx<'tcx, Self>, kind: mir::RetagKind, - val: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + val: &ImmTy<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx>> { if ecx.machine.borrow_tracker.is_some() { ecx.retag_ptr_value(kind, val) } else { @@ -1308,7 +1298,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn retag_place_contents( ecx: &mut InterpCx<'tcx, Self>, kind: mir::RetagKind, - place: &PlaceTy<'tcx, Provenance>, + place: &PlaceTy<'tcx>, ) -> InterpResult<'tcx> { if ecx.machine.borrow_tracker.is_some() { ecx.retag_place_contents(kind, place)?; @@ -1318,7 +1308,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn protect_in_place_function_argument( ecx: &mut InterpCx<'tcx, Self>, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { // If we have a borrow tracker, we also have it set up protection so that all reads *and // writes* during this call are insta-UB. @@ -1473,7 +1463,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn after_local_allocated( ecx: &mut InterpCx<'tcx, Self>, local: mir::Local, - mplace: &MPlaceTy<'tcx, Provenance>, + mplace: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let Some(Provenance::Concrete { alloc_id, .. }) = mplace.ptr().provenance else { panic!("after_local_allocated should only be called on fresh allocations"); @@ -1490,14 +1480,14 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { span: Span, layout: Option<TyAndLayout<'tcx>>, eval: F, - ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>> + ) -> InterpResult<'tcx, OpTy<'tcx>> where F: Fn( &InterpCx<'tcx, Self>, mir::Const<'tcx>, Span, Option<TyAndLayout<'tcx>>, - ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>>, + ) -> InterpResult<'tcx, OpTy<'tcx>>, { let frame = ecx.active_thread_stack().last().unwrap(); let mut cache = ecx.machine.const_cache.borrow_mut(); diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index c04f12c339e..bc44e672bd8 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs @@ -12,9 +12,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn binary_ptr_op( &self, bin_op: mir::BinOp, - left: &ImmTy<'tcx, Provenance>, - right: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + left: &ImmTy<'tcx>, + right: &ImmTy<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx>> { use rustc_middle::mir::BinOp::*; let this = self.eval_context_ref(); diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs index 03b6cfdce7b..af980ca4819 100644 --- a/src/tools/miri/src/provenance_gc.rs +++ b/src/tools/miri/src/provenance_gc.rs @@ -56,21 +56,21 @@ impl VisitProvenance for Provenance { } } -impl VisitProvenance for Pointer<Provenance> { +impl VisitProvenance for StrictPointer { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let (prov, _offset) = self.into_parts(); prov.visit_provenance(visit); } } -impl VisitProvenance for Pointer<Option<Provenance>> { +impl VisitProvenance for Pointer { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let (prov, _offset) = self.into_parts(); prov.visit_provenance(visit); } } -impl VisitProvenance for Scalar<Provenance> { +impl VisitProvenance for Scalar { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { match self { Scalar::Ptr(ptr, _) => ptr.visit_provenance(visit), @@ -103,20 +103,20 @@ impl VisitProvenance for MemPlaceMeta<Provenance> { } } -impl VisitProvenance for ImmTy<'_, Provenance> { +impl VisitProvenance for ImmTy<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { (**self).visit_provenance(visit) } } -impl VisitProvenance for MPlaceTy<'_, Provenance> { +impl VisitProvenance for MPlaceTy<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { self.ptr().visit_provenance(visit); self.meta().visit_provenance(visit); } } -impl VisitProvenance for PlaceTy<'_, Provenance> { +impl VisitProvenance for PlaceTy<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { match self.as_mplace_or_local() { Either::Left(mplace) => mplace.visit_provenance(visit), @@ -125,7 +125,7 @@ impl VisitProvenance for PlaceTy<'_, Provenance> { } } -impl VisitProvenance for OpTy<'_, Provenance> { +impl VisitProvenance for OpTy<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { match self.as_mplace_or_imm() { Either::Left(mplace) => mplace.visit_provenance(visit), diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs index bbe4bdd8450..7b0c54d763e 100644 --- a/src/tools/miri/src/shims/alloc.rs +++ b/src/tools/miri/src/shims/alloc.rs @@ -92,11 +92,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn malloc( - &mut self, - size: u64, - zero_init: bool, - ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> { + fn malloc(&mut self, size: u64, zero_init: bool) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); let align = this.malloc_align(size); let ptr = this.allocate_ptr(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; @@ -113,10 +109,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn posix_memalign( &mut self, - memptr: &OpTy<'tcx, Provenance>, - align: &OpTy<'tcx, Provenance>, - size: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + memptr: &OpTy<'tcx>, + align: &OpTy<'tcx>, + size: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let memptr = this.deref_pointer(memptr)?; let align = this.read_target_usize(align)?; @@ -137,7 +133,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn free(&mut self, ptr: Pointer<Option<Provenance>>) -> 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, MiriMemoryKind::C.into())?; @@ -145,11 +141,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn realloc( - &mut self, - old_ptr: Pointer<Option<Provenance>>, - new_size: u64, - ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> { + fn realloc(&mut self, old_ptr: Pointer, new_size: u64) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); let new_align = this.malloc_align(new_size); if this.ptr_is_null(old_ptr)? { @@ -175,9 +167,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn aligned_alloc( &mut self, - align: &OpTy<'tcx, Provenance>, - size: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> { + align: &OpTy<'tcx>, + size: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); let align = this.read_target_usize(align)?; let size = this.read_target_usize(size)?; diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index 6ec65a16b8a..06be9c1e63e 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -11,8 +11,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let [flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -31,8 +31,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; @@ -110,7 +110,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn resolve_frame_pointer( &mut self, - ptr: &OpTy<'tcx, Provenance>, + ptr: &OpTy<'tcx>, ) -> InterpResult<'tcx, (Instance<'tcx>, Loc, String, String)> { let this = self.eval_context_mut(); @@ -140,8 +140,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let [ptr, flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -218,7 +218,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Provenance>], + args: &[OpTy<'tcx>], ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs index 9330ac0b4dd..17ac2638a69 100644 --- a/src/tools/miri/src/shims/extern_static.rs +++ b/src/tools/miri/src/shims/extern_static.rs @@ -6,7 +6,7 @@ impl<'tcx> MiriMachine<'tcx> { fn alloc_extern_static( this: &mut MiriInterpCx<'tcx>, name: &str, - val: ImmTy<'tcx, Provenance>, + val: ImmTy<'tcx>, ) -> InterpResult<'tcx> { let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?; this.write_immediate(*val, &place)?; diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 6dfd9866cae..898fc111fd4 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -40,8 +40,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> { @@ -123,8 +123,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, sym: DynSym, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ret: Option<mir::BasicBlock>, unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { @@ -208,8 +208,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); @@ -238,11 +238,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // ``` // fn shim_name( // &mut self, - // arg1: &OpTy<'tcx, Provenance>, - // arg2: &OpTy<'tcx, Provenance>, - // arg3: &OpTy<'tcx, Provenance>, - // arg4: &OpTy<'tcx, Provenance>) - // -> InterpResult<'tcx, Scalar<Provenance>> { + // arg1: &OpTy<'tcx>, + // arg2: &OpTy<'tcx>, + // arg3: &OpTy<'tcx>, + // arg4: &OpTy<'tcx>) + // -> InterpResult<'tcx, Scalar> { // let this = self.eval_context_mut(); // // // First thing: load all the arguments. Details depend on the shim. diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs index cc5cc75332a..40697e17ba1 100644 --- a/src/tools/miri/src/shims/native_lib.rs +++ b/src/tools/miri/src/shims/native_lib.rs @@ -14,10 +14,10 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { fn call_native_with_args<'a>( &mut self, link_name: Symbol, - dest: &MPlaceTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx>, ptr: CodePtr, libffi_args: Vec<libffi::high::Arg<'a>>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, ImmTy<'tcx>> { let this = self.eval_context_mut(); // Call the function (`ptr`) with arguments `libffi_args`, and obtain the return value @@ -132,8 +132,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn call_native_fn( &mut self, link_name: Symbol, - dest: &MPlaceTy<'tcx, Provenance>, - args: &[OpTy<'tcx, Provenance>], + dest: &MPlaceTy<'tcx>, + args: &[OpTy<'tcx>], ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); // Get the pointer to the function in the shared object file if it exists. @@ -216,10 +216,7 @@ impl<'a> CArg { /// 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> { +fn imm_to_carg<'tcx>(v: ImmTy<'tcx>, 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. diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs index c00e4384bab..68eca5a3a0f 100644 --- a/src/tools/miri/src/shims/os_str.rs +++ b/src/tools/miri/src/shims/os_str.rs @@ -34,10 +34,7 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. - fn read_os_str_from_c_str<'a>( - &'a self, - ptr: Pointer<Option<Provenance>>, - ) -> InterpResult<'tcx, &'a OsStr> + fn read_os_str_from_c_str<'a>(&'a self, ptr: Pointer) -> InterpResult<'tcx, &'a OsStr> where 'tcx: 'a, { @@ -48,10 +45,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, /// which is what the Windows APIs usually handle. - fn read_os_str_from_wide_str<'a>( - &'a self, - ptr: Pointer<Option<Provenance>>, - ) -> InterpResult<'tcx, OsString> + fn read_os_str_from_wide_str<'a>(&'a self, ptr: Pointer) -> InterpResult<'tcx, OsString> where 'tcx: 'a, { @@ -76,7 +70,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_os_str_to_c_str( &mut self, os_str: &OsStr, - ptr: Pointer<Option<Provenance>>, + ptr: Pointer, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let bytes = os_str.as_encoded_bytes(); @@ -88,7 +82,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_os_str_to_wide_str_helper( &mut self, os_str: &OsStr, - ptr: Pointer<Option<Provenance>>, + ptr: Pointer, size: u64, truncate: bool, ) -> InterpResult<'tcx, (bool, u64)> { @@ -125,7 +119,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_os_str_to_wide_str( &mut self, os_str: &OsStr, - ptr: Pointer<Option<Provenance>>, + ptr: Pointer, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { self.write_os_str_to_wide_str_helper(os_str, ptr, size, /*truncate*/ false) @@ -136,7 +130,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_os_str_to_wide_str_truncated( &mut self, os_str: &OsStr, - ptr: Pointer<Option<Provenance>>, + ptr: Pointer, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { self.write_os_str_to_wide_str_helper(os_str, ptr, size, /*truncate*/ true) @@ -147,7 +141,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, os_str: &OsStr, memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> { + ) -> InterpResult<'tcx, Pointer> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. let this = self.eval_context_mut(); @@ -163,7 +157,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, os_str: &OsStr, memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> { + ) -> InterpResult<'tcx, Pointer> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. let this = self.eval_context_mut(); @@ -175,10 +169,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. - fn read_path_from_c_str<'a>( - &'a self, - ptr: Pointer<Option<Provenance>>, - ) -> InterpResult<'tcx, Cow<'a, Path>> + fn read_path_from_c_str<'a>(&'a self, ptr: Pointer) -> InterpResult<'tcx, Cow<'a, Path>> where 'tcx: 'a, { @@ -192,10 +183,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Read a null-terminated sequence of `u16`s, and perform path separator conversion if needed. - fn read_path_from_wide_str( - &self, - ptr: Pointer<Option<Provenance>>, - ) -> InterpResult<'tcx, PathBuf> { + fn read_path_from_wide_str(&self, ptr: Pointer) -> InterpResult<'tcx, PathBuf> { let this = self.eval_context_ref(); let os_str = this.read_os_str_from_wide_str(ptr)?; @@ -207,7 +195,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_path_to_c_str( &mut self, path: &Path, - ptr: Pointer<Option<Provenance>>, + ptr: Pointer, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); @@ -221,7 +209,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_path_to_wide_str( &mut self, path: &Path, - ptr: Pointer<Option<Provenance>>, + ptr: Pointer, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); @@ -235,7 +223,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_path_to_wide_str_truncated( &mut self, path: &Path, - ptr: Pointer<Option<Provenance>>, + ptr: Pointer, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); @@ -250,7 +238,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, path: &Path, memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> { + ) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); let os_str = this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); @@ -263,7 +251,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, path: &Path, memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> { + ) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); let os_str = this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 8aed6d4f463..ef832f5bbbd 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -23,11 +23,11 @@ use helpers::check_arg_count; #[derive(Debug)] pub struct CatchUnwindData<'tcx> { /// The `catch_fn` callback to call in case of a panic. - catch_fn: Pointer<Option<Provenance>>, + catch_fn: Pointer, /// The `data` argument for that callback. - data: Scalar<Provenance>, + data: Scalar, /// The return place from the original call to `try`. - dest: MPlaceTy<'tcx, Provenance>, + dest: MPlaceTy<'tcx>, /// The return block from the original call to `try`. ret: Option<mir::BasicBlock>, } @@ -45,7 +45,7 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Handles the special `miri_start_unwind` intrinsic, which is called /// by libpanic_unwind to delegate the actual unwinding process to Miri. - fn handle_miri_start_unwind(&mut self, payload: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn handle_miri_start_unwind(&mut self, payload: &OpTy<'tcx>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); trace!("miri_start_unwind: {:?}", this.frame().instance); @@ -60,8 +60,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Handles the `try` intrinsic, the underlying implementation of `std::panicking::try`. fn handle_catch_unwind( &mut self, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ret: Option<mir::BasicBlock>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 9fb7a735c30..ae17196f0b7 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -18,9 +18,9 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn clock_gettime( &mut self, - clk_id_op: &OpTy<'tcx, Provenance>, - tp_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + clk_id_op: &OpTy<'tcx>, + tp_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { // This clock support is deliberately minimal because a lot of clock types have fiddly // properties (is it possible for Miri to be suspended independently of the host?). If you // have a use for another clock type, please open an issue. @@ -78,7 +78,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.check_no_isolation("`clock_gettime` with `REALTIME` clocks")?; system_time_to_duration(&SystemTime::now())? } else if relative_clocks.contains(&clk_id) { - this.machine.clock.now().duration_since(this.machine.clock.anchor()) + this.machine.clock.now().duration_since(this.machine.clock.epoch()) } else { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; @@ -93,11 +93,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_i32(0)) } - fn gettimeofday( - &mut self, - tv_op: &OpTy<'tcx, Provenance>, - tz_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn gettimeofday(&mut self, tv_op: &OpTy<'tcx>, tz_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("gettimeofday"); @@ -127,9 +123,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://linux.die.net/man/3/localtime_r fn localtime_r( &mut self, - timep: &OpTy<'tcx, Provenance>, - result_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> { + timep: &OpTy<'tcx>, + result_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("localtime_r"); @@ -212,7 +208,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn GetSystemTimeAsFileTime( &mut self, shim_name: &str, - LPFILETIME_op: &OpTy<'tcx, Provenance>, + LPFILETIME_op: &OpTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -242,15 +238,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(non_snake_case)] fn QueryPerformanceCounter( &mut self, - lpPerformanceCount_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + lpPerformanceCount_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("windows", "QueryPerformanceCounter"); // QueryPerformanceCounter uses a hardware counter as its basis. // Miri will emulate a counter with a resolution of 1 nanosecond. - let duration = this.machine.clock.now().duration_since(this.machine.clock.anchor()); + let duration = this.machine.clock.now().duration_since(this.machine.clock.epoch()); let qpc = i64::try_from(duration.as_nanos()).map_err(|_| { err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported") })?; @@ -261,8 +257,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(non_snake_case)] fn QueryPerformanceFrequency( &mut self, - lpFrequency_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + lpFrequency_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("windows", "QueryPerformanceFrequency"); @@ -279,24 +275,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_i32(-1)) // Return non-zero on success } - fn mach_absolute_time(&self) -> InterpResult<'tcx, Scalar<Provenance>> { + fn mach_absolute_time(&self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); this.assert_target_os("macos", "mach_absolute_time"); // This returns a u64, with time units determined dynamically by `mach_timebase_info`. // We return plain nanoseconds. - let duration = this.machine.clock.now().duration_since(this.machine.clock.anchor()); + let duration = this.machine.clock.now().duration_since(this.machine.clock.epoch()); let res = u64::try_from(duration.as_nanos()).map_err(|_| { err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported") })?; Ok(Scalar::from_u64(res)) } - fn mach_timebase_info( - &mut self, - info_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + fn mach_timebase_info(&mut self, info_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("macos", "mach_timebase_info"); @@ -313,8 +306,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn nanosleep( &mut self, - req_op: &OpTy<'tcx, Provenance>, - _rem: &OpTy<'tcx, Provenance>, // Signal handlers are not supported, so rem will never be written to. + req_op: &OpTy<'tcx>, + _rem: &OpTy<'tcx>, // Signal handlers are not supported, so rem will never be written to. ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -330,16 +323,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return Ok(-1); } }; - // If adding the duration overflows, let's just sleep for an hour. Waking up early is always acceptable. - let now = this.machine.clock.now(); - let timeout_time = now - .checked_add(duration) - .unwrap_or_else(|| now.checked_add(Duration::from_secs(3600)).unwrap()); - let timeout_time = Timeout::Monotonic(timeout_time); this.block_thread( BlockReason::Sleep, - Some(timeout_time), + Some((TimeoutClock::Monotonic, TimeoutAnchor::Relative, duration)), callback!( @capture<'tcx> {} @unblock = |_this| { panic!("sleeping thread unblocked before time is up") } @@ -350,7 +337,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } #[allow(non_snake_case)] - fn Sleep(&mut self, timeout: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn Sleep(&mut self, timeout: &OpTy<'tcx>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.assert_target_os("windows", "Sleep"); @@ -358,12 +345,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let timeout_ms = this.read_scalar(timeout)?.to_u32()?; let duration = Duration::from_millis(timeout_ms.into()); - let timeout_time = this.machine.clock.now().checked_add(duration).unwrap(); - let timeout_time = Timeout::Monotonic(timeout_time); this.block_thread( BlockReason::Sleep, - Some(timeout_time), + Some((TimeoutClock::Monotonic, TimeoutAnchor::Relative, duration)), callback!( @capture<'tcx> {} @unblock = |_this| { panic!("sleeping thread unblocked before time is up") } diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs index fa52b036ce9..c91386fa877 100644 --- a/src/tools/miri/src/shims/tls.rs +++ b/src/tools/miri/src/shims/tls.rs @@ -16,7 +16,7 @@ pub type TlsKey = u128; pub struct TlsEntry<'tcx> { /// The data for this key. None is used to represent NULL. /// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.) - data: BTreeMap<ThreadId, Scalar<Provenance>>, + data: BTreeMap<ThreadId, Scalar>, dtor: Option<ty::Instance<'tcx>>, } @@ -38,7 +38,7 @@ pub struct TlsData<'tcx> { /// A single per thread destructor of the thread local storage (that's how /// things work on macOS) with a data argument. - macos_thread_dtors: BTreeMap<ThreadId, (ty::Instance<'tcx>, Scalar<Provenance>)>, + macos_thread_dtors: BTreeMap<ThreadId, (ty::Instance<'tcx>, Scalar)>, } impl<'tcx> Default for TlsData<'tcx> { @@ -86,7 +86,7 @@ impl<'tcx> TlsData<'tcx> { key: TlsKey, thread_id: ThreadId, cx: &impl HasDataLayout, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + ) -> InterpResult<'tcx, Scalar> { match self.keys.get(&key) { Some(TlsEntry { data, .. }) => { let value = data.get(&thread_id).copied(); @@ -101,7 +101,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: TlsKey, thread_id: ThreadId, - new_data: Scalar<Provenance>, + new_data: Scalar, cx: &impl HasDataLayout, ) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { @@ -132,7 +132,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, - data: Scalar<Provenance>, + data: Scalar, ) -> InterpResult<'tcx> { if self.macos_thread_dtors.insert(thread, (dtor, data)).is_some() { throw_unsup_format!( @@ -165,7 +165,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: Option<TlsKey>, thread_id: ThreadId, - ) -> Option<(ty::Instance<'tcx>, Scalar<Provenance>, TlsKey)> { + ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::ops::Bound::*; let thread_local = &mut self.keys; @@ -228,7 +228,7 @@ enum TlsDtorsStatePriv<'tcx> { PthreadDtors(RunningDtorState), /// For Windows Dtors, we store the list of functions that we still have to call. /// These are functions from the magic `.CRT$XLB` linker section. - WindowsDtors(Vec<ImmTy<'tcx, Provenance>>), + WindowsDtors(Vec<ImmTy<'tcx>>), Done, } @@ -297,7 +297,7 @@ impl<'tcx> EvalContextPrivExt<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Schedule TLS destructors for Windows. /// On windows, TLS destructors are managed by std. - fn lookup_windows_tls_dtors(&mut self) -> InterpResult<'tcx, Vec<ImmTy<'tcx, Provenance>>> { + fn lookup_windows_tls_dtors(&mut self) -> InterpResult<'tcx, Vec<ImmTy<'tcx>>> { let this = self.eval_context_mut(); // Windows has a special magic linker section that is run on certain events. @@ -305,7 +305,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(this.lookup_link_section(".CRT$XLB")?) } - fn schedule_windows_tls_dtor(&mut self, dtor: ImmTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn schedule_windows_tls_dtor(&mut self, dtor: ImmTy<'tcx>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let dtor = dtor.to_scalar().to_pointer(this)?; diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs index 8a6e025ee18..42552a51eda 100644 --- a/src/tools/miri/src/shims/unix/android/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs @@ -13,8 +13,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); match link_name.as_str() { diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs index 26096910aa1..2f78d0f4296 100644 --- a/src/tools/miri/src/shims/unix/env.rs +++ b/src/tools/miri/src/shims/unix/env.rs @@ -13,10 +13,10 @@ use crate::*; pub struct UnixEnvVars<'tcx> { /// Stores pointers to the environment variables. These variables must be stored as /// null-terminated target strings (c_str or wide_str) with the `"{name}={value}"` format. - map: FxHashMap<OsString, Pointer<Option<Provenance>>>, + map: FxHashMap<OsString, Pointer>, /// Place where the `environ` static is stored. Lazily initialized, but then never changes. - environ: MPlaceTy<'tcx, Provenance>, + environ: MPlaceTy<'tcx>, } impl VisitProvenance for UnixEnvVars<'_> { @@ -65,7 +65,7 @@ impl<'tcx> UnixEnvVars<'tcx> { Ok(()) } - pub(crate) fn environ(&self) -> Pointer<Option<Provenance>> { + pub(crate) fn environ(&self) -> Pointer { self.environ.ptr() } @@ -73,7 +73,7 @@ impl<'tcx> UnixEnvVars<'tcx> { &self, ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, name: &OsStr, - ) -> InterpResult<'tcx, Option<Pointer<Option<Provenance>>>> { + ) -> InterpResult<'tcx, Option<Pointer>> { // We don't care about the value as we have the `map` to keep track of everything, // but we do want to do this read so it shows up as a data race. let _vars_ptr = ecx.read_pointer(&self.environ)?; @@ -109,7 +109,7 @@ fn alloc_env_var<'tcx>( ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>, name: &OsStr, value: &OsStr, -) -> InterpResult<'tcx, Pointer<Option<Provenance>>> { +) -> InterpResult<'tcx, Pointer> { let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); @@ -119,8 +119,8 @@ fn alloc_env_var<'tcx>( /// Allocates an `environ` block with the given list of pointers. fn alloc_environ_block<'tcx>( ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>, - mut vars: Vec<Pointer<Option<Provenance>>>, -) -> InterpResult<'tcx, Pointer<Option<Provenance>>> { + mut vars: Vec<Pointer>, +) -> InterpResult<'tcx, Pointer> { // Add trailing null. vars.push(Pointer::null()); // Make an array with all these pointers inside Miri. @@ -139,10 +139,7 @@ fn alloc_environ_block<'tcx>( impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn getenv( - &mut self, - name_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> { + fn getenv(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("getenv"); @@ -153,11 +150,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(var_ptr.unwrap_or_else(Pointer::null)) } - fn setenv( - &mut self, - name_op: &OpTy<'tcx, Provenance>, - value_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn setenv(&mut self, name_op: &OpTy<'tcx>, value_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("setenv"); @@ -187,7 +180,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn unsetenv(&mut self, name_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn unsetenv(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("unsetenv"); @@ -213,11 +206,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn getcwd( - &mut self, - buf_op: &OpTy<'tcx, Provenance>, - size_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> { + fn getcwd(&mut self, buf_op: &OpTy<'tcx>, size_op: &OpTy<'tcx>) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("getcwd"); @@ -245,7 +234,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Pointer::null()) } - fn chdir(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn chdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("chdir"); diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 5fdd77a0cbd..b6ac841dc9f 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -273,7 +273,7 @@ impl FdTable { impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn fcntl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { + fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); if args.len() < 2 { @@ -329,7 +329,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn close(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, Scalar<Provenance>> { + fn close(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -355,12 +355,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok((-1).into()) } - fn read( - &mut self, - fd: i32, - buf: Pointer<Option<Provenance>>, - count: u64, - ) -> InterpResult<'tcx, i64> { + fn read(&mut self, fd: i32, buf: Pointer, count: u64) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -409,12 +404,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn write( - &mut self, - fd: i32, - buf: Pointer<Option<Provenance>>, - count: u64, - ) -> InterpResult<'tcx, i64> { + fn write(&mut self, fd: i32, buf: Pointer, count: u64) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 052715e239f..2282099fa0d 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -43,8 +43,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); @@ -326,7 +326,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let name = this.read_scalar(name)?.to_i32()?; // FIXME: Which of these are POSIX, and which are GNU/Linux? // At least the names seem to all also exist on macOS. - let sysconfs: &[(&str, fn(&MiriInterpCx<'_>) -> Scalar<Provenance>)] = &[ + let sysconfs: &[(&str, fn(&MiriInterpCx<'_>) -> Scalar)] = &[ ("_SC_PAGESIZE", |this| Scalar::from_int(this.machine.page_size, this.pointer_size())), ("_SC_NPROCESSORS_CONF", |this| Scalar::from_int(this.machine.num_cpus, this.pointer_size())), ("_SC_NPROCESSORS_ONLN", |this| Scalar::from_int(this.machine.num_cpus, this.pointer_size())), diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 30eb88151e4..36f25767a8e 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -14,8 +14,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); match link_name.as_str() { diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 8e3d547b075..c8805f054ec 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -91,7 +91,7 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> { fn macos_stat_write_buf( &mut self, metadata: FileMetadata, - buf_op: &OpTy<'tcx, Provenance>, + buf_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -180,7 +180,7 @@ struct OpenDir { read_dir: ReadDir, /// The most recent entry returned by readdir(). /// Will be freed by the next call. - entry: Option<Pointer<Option<Provenance>>>, + entry: Option<Pointer>, } impl OpenDir { @@ -256,7 +256,7 @@ fn maybe_sync_file( impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn open(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { + fn open(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> { if args.len() < 2 { throw_ub_format!( "incorrect number of arguments for `open`: got {}, expected at least 2", @@ -389,12 +389,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.try_unwrap_io_result(fd) } - fn lseek64( - &mut self, - fd: i32, - offset: i128, - whence: i32, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + fn lseek64(&mut self, fd: i32, offset: i128, whence: i32) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -425,7 +420,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_i64(result)) } - fn unlink(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn unlink(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; @@ -443,8 +438,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn symlink( &mut self, - target_op: &OpTy<'tcx, Provenance>, - linkpath_op: &OpTy<'tcx, Provenance>, + target_op: &OpTy<'tcx>, + linkpath_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { #[cfg(unix)] fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { @@ -474,9 +469,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn macos_fbsd_stat( &mut self, - path_op: &OpTy<'tcx, Provenance>, - buf_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + path_op: &OpTy<'tcx>, + buf_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { @@ -506,9 +501,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `lstat` is used to get symlink metadata. fn macos_fbsd_lstat( &mut self, - path_op: &OpTy<'tcx, Provenance>, - buf_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + path_op: &OpTy<'tcx>, + buf_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { @@ -536,9 +531,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn macos_fbsd_fstat( &mut self, - fd_op: &OpTy<'tcx, Provenance>, - buf_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + fd_op: &OpTy<'tcx>, + buf_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { @@ -563,11 +558,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn linux_statx( &mut self, - dirfd_op: &OpTy<'tcx, Provenance>, // Should be an `int` - pathname_op: &OpTy<'tcx, Provenance>, // Should be a `const char *` - flags_op: &OpTy<'tcx, Provenance>, // Should be an `int` - mask_op: &OpTy<'tcx, Provenance>, // Should be an `unsigned int` - statxbuf_op: &OpTy<'tcx, Provenance>, // Should be a `struct statx *` + dirfd_op: &OpTy<'tcx>, // Should be an `int` + pathname_op: &OpTy<'tcx>, // Should be a `const char *` + flags_op: &OpTy<'tcx>, // Should be an `int` + mask_op: &OpTy<'tcx>, // Should be an `unsigned int` + statxbuf_op: &OpTy<'tcx>, // Should be a `struct statx *` ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -745,8 +740,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn rename( &mut self, - oldpath_op: &OpTy<'tcx, Provenance>, - newpath_op: &OpTy<'tcx, Provenance>, + oldpath_op: &OpTy<'tcx>, + newpath_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -774,11 +769,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.try_unwrap_io_result(result) } - fn mkdir( - &mut self, - path_op: &OpTy<'tcx, Provenance>, - mode_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn mkdir(&mut self, path_op: &OpTy<'tcx>, mode_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); #[cfg_attr(not(unix), allow(unused_variables))] @@ -813,7 +804,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.try_unwrap_io_result(result) } - fn rmdir(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn rmdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; @@ -830,10 +821,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.try_unwrap_io_result(result) } - fn opendir( - &mut self, - name_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + fn opendir(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let name = this.read_path_from_c_str(this.read_pointer(name_op)?)?; @@ -864,10 +852,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn linux_readdir64( - &mut self, - dirp_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + fn linux_readdir64(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("linux", "readdir64"); @@ -915,7 +900,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { dirent64_layout.align.abi, MiriMemoryKind::Runtime.into(), )?; - let entry: Pointer<Option<Provenance>> = entry.into(); + let entry: Pointer = entry.into(); // If the host is a Unix system, fill in the inode number with its real value. // If not, use 0 as a fallback value. @@ -962,10 +947,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn macos_fbsd_readdir_r( &mut self, - dirp_op: &OpTy<'tcx, Provenance>, - entry_op: &OpTy<'tcx, Provenance>, - result_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + dirp_op: &OpTy<'tcx>, + entry_op: &OpTy<'tcx>, + result_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { @@ -1083,7 +1068,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { })) } - fn closedir(&mut self, dirp_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn closedir(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let dirp = this.read_target_usize(dirp_op)?; @@ -1106,7 +1091,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn ftruncate64(&mut self, fd: i32, length: i128) -> InterpResult<'tcx, Scalar<Provenance>> { + fn ftruncate64(&mut self, fd: i32, length: i128) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); // Reject if isolation is enabled. @@ -1147,7 +1132,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn fsync(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn fsync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { // On macOS, `fsync` (unlike `fcntl(F_FULLFSYNC)`) does not wait for the // underlying disk to finish writing. In the interest of host compatibility, // we conservatively implement this with `sync_all`, which @@ -1182,7 +1167,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.try_unwrap_io_result(io_result) } - fn fdatasync(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn fdatasync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -1209,11 +1194,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn sync_file_range( &mut self, - fd_op: &OpTy<'tcx, Provenance>, - offset_op: &OpTy<'tcx, Provenance>, - nbytes_op: &OpTy<'tcx, Provenance>, - flags_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + fd_op: &OpTy<'tcx>, + offset_op: &OpTy<'tcx>, + nbytes_op: &OpTy<'tcx>, + flags_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -1259,9 +1244,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn readlink( &mut self, - pathname_op: &OpTy<'tcx, Provenance>, - buf_op: &OpTy<'tcx, Provenance>, - bufsize_op: &OpTy<'tcx, Provenance>, + pathname_op: &OpTy<'tcx>, + buf_op: &OpTy<'tcx>, + bufsize_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); @@ -1302,10 +1287,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn isatty( - &mut self, - miri_fd: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + fn isatty(&mut self, miri_fd: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); // "returns 1 if fd is an open file descriptor referring to a terminal; // otherwise 0 is returned, and errno is set to indicate the error" @@ -1326,9 +1308,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn realpath( &mut self, - path_op: &OpTy<'tcx, Provenance>, - processed_path_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + path_op: &OpTy<'tcx>, + processed_path_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("realpath"); @@ -1384,7 +1366,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } } - fn mkstemp(&mut self, template_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn mkstemp(&mut self, template_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { use rand::seq::SliceRandom; // POSIX defines the template string. @@ -1531,7 +1513,7 @@ fn extract_sec_and_nsec<'tcx>( /// Stores a file's metadata in order to avoid code duplication in the different metadata related /// shims. struct FileMetadata { - mode: Scalar<Provenance>, + mode: Scalar, size: u64, created: Option<(u64, u32)>, accessed: Option<(u64, u32)>, diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs index 50868e60e95..aa4dc982870 100644 --- a/src/tools/miri/src/shims/unix/linux/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux/epoll.rs @@ -25,10 +25,10 @@ struct Epoll { struct EpollEvent { #[allow(dead_code)] events: u32, - /// `Scalar<Provenance>` is used to represent the + /// `Scalar` is used to represent the /// `epoll_data` type union. #[allow(dead_code)] - data: Scalar<Provenance>, + data: Scalar, } impl FileDescription for Epoll { @@ -51,10 +51,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// is 0, then this function is the same as `epoll_create()`. /// /// <https://linux.die.net/man/2/epoll_create1> - fn epoll_create1( - &mut self, - flags: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + fn epoll_create1(&mut self, flags: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let flags = this.read_scalar(flags)?.to_i32()?; @@ -85,11 +82,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// <https://linux.die.net/man/2/epoll_ctl> fn epoll_ctl( &mut self, - epfd: &OpTy<'tcx, Provenance>, - op: &OpTy<'tcx, Provenance>, - fd: &OpTy<'tcx, Provenance>, - event: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + epfd: &OpTy<'tcx>, + op: &OpTy<'tcx>, + fd: &OpTy<'tcx>, + event: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let epfd = this.read_scalar(epfd)?.to_i32()?; @@ -167,11 +164,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// <https://man7.org/linux/man-pages/man2/epoll_wait.2.html> fn epoll_wait( &mut self, - epfd: &OpTy<'tcx, Provenance>, - events: &OpTy<'tcx, Provenance>, - maxevents: &OpTy<'tcx, Provenance>, - timeout: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + epfd: &OpTy<'tcx>, + events: &OpTy<'tcx>, + maxevents: &OpTy<'tcx>, + timeout: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let epfd = this.read_scalar(epfd)?.to_i32()?; diff --git a/src/tools/miri/src/shims/unix/linux/eventfd.rs b/src/tools/miri/src/shims/unix/linux/eventfd.rs index 1447e498fd7..cae5abca3bd 100644 --- a/src/tools/miri/src/shims/unix/linux/eventfd.rs +++ b/src/tools/miri/src/shims/unix/linux/eventfd.rs @@ -1,14 +1,21 @@ //! Linux `eventfd` implementation. -//! Currently just a stub. use std::io; +use std::io::{Error, ErrorKind}; +use std::mem; use rustc_target::abi::Endian; use crate::shims::unix::*; -use crate::*; +use crate::{concurrency::VClock, *}; use self::shims::unix::fd::FileDescriptor; +// We'll only do reads and writes in chunks of size u64. +const U64_ARRAY_SIZE: usize = mem::size_of::<u64>(); + +/// Maximum value that the eventfd counter can hold. +const MAX_COUNTER: u64 = u64::MAX - 1; + /// A kind of file descriptor created by `eventfd`. /// The `Event` type isn't currently written to by `eventfd`. /// The interface is meant to keep track of objects associated @@ -20,7 +27,9 @@ use self::shims::unix::fd::FileDescriptor; struct Event { /// The object contains an unsigned 64-bit integer (uint64_t) counter that is maintained by the /// kernel. This counter is initialized with the value specified in the argument initval. - val: u64, + counter: u64, + is_nonblock: bool, + clock: VClock, } impl FileDescription for Event { @@ -35,6 +44,38 @@ impl FileDescription for Event { Ok(Ok(())) } + /// Read the counter in the buffer and return the counter if succeeded. + fn read<'tcx>( + &mut self, + _communicate_allowed: bool, + bytes: &mut [u8], + ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<usize>> { + // Check the size of slice, and return error only if the size of the slice < 8. + let Some(bytes) = bytes.first_chunk_mut::<U64_ARRAY_SIZE>() else { + return Ok(Err(Error::from(ErrorKind::InvalidInput))); + }; + // Block when counter == 0. + if self.counter == 0 { + if self.is_nonblock { + return Ok(Err(Error::from(ErrorKind::WouldBlock))); + } else { + //FIXME: blocking is not supported + throw_unsup_format!("eventfd: blocking is unsupported"); + } + } else { + // Synchronize with all prior `write` calls to this FD. + ecx.acquire_clock(&self.clock); + // Return the counter in the host endianness using the buffer provided by caller. + *bytes = match ecx.tcx.sess.target.endian { + Endian::Little => self.counter.to_le_bytes(), + Endian::Big => self.counter.to_be_bytes(), + }; + self.counter = 0; + return Ok(Ok(U64_ARRAY_SIZE)); + } + } + /// A write call adds the 8-byte integer value supplied in /// its buffer (in native endianness) to the counter. The maximum value that may be /// stored in the counter is the largest unsigned 64-bit value @@ -53,16 +94,39 @@ impl FileDescription for Event { bytes: &[u8], ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx, io::Result<usize>> { - let bytes: [u8; 8] = bytes.try_into().unwrap(); // FIXME fail gracefully when this has the wrong size - // Convert from target endianness to host endianness. + // Check the size of slice, and return error only if the size of the slice < 8. + let Some(bytes) = bytes.first_chunk::<U64_ARRAY_SIZE>() else { + return Ok(Err(Error::from(ErrorKind::InvalidInput))); + }; + // Convert from bytes to int according to host endianness. let num = match ecx.tcx.sess.target.endian { - Endian::Little => u64::from_le_bytes(bytes), - Endian::Big => u64::from_be_bytes(bytes), + Endian::Little => u64::from_le_bytes(*bytes), + Endian::Big => u64::from_be_bytes(*bytes), + }; + // u64::MAX as input is invalid because the maximum value of counter is u64::MAX - 1. + if num == u64::MAX { + return Ok(Err(Error::from(ErrorKind::InvalidInput))); + } + // If the addition does not let the counter to exceed the maximum value, update the counter. + // Else, block. + match self.counter.checked_add(num) { + Some(new_count @ 0..=MAX_COUNTER) => { + // Future `read` calls will synchronize with this write, so update the FD clock. + if let Some(clock) = &ecx.release_clock() { + self.clock.join(clock); + } + self.counter = new_count; + } + None | Some(u64::MAX) => { + if self.is_nonblock { + return Ok(Err(Error::from(ErrorKind::WouldBlock))); + } else { + //FIXME: blocking is not supported + throw_unsup_format!("eventfd: blocking is unsupported"); + } + } }; - // FIXME handle blocking when addition results in exceeding the max u64 value - // or fail with EAGAIN if the file descriptor is nonblocking. - self.val = self.val.checked_add(num).unwrap(); - Ok(Ok(8)) + Ok(Ok(U64_ARRAY_SIZE)) } } @@ -84,34 +148,43 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// `EFD_SEMAPHORE` - miri does not support semaphore-like semantics. /// /// <https://linux.die.net/man/2/eventfd> - fn eventfd( - &mut self, - val: &OpTy<'tcx, Provenance>, - flags: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + fn eventfd(&mut self, val: &OpTy<'tcx>, flags: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); + // eventfd is Linux specific. + this.assert_target_os("linux", "eventfd"); + let val = this.read_scalar(val)?.to_u32()?; - let flags = this.read_scalar(flags)?.to_i32()?; + let mut flags = this.read_scalar(flags)?.to_i32()?; let efd_cloexec = this.eval_libc_i32("EFD_CLOEXEC"); let efd_nonblock = this.eval_libc_i32("EFD_NONBLOCK"); let efd_semaphore = this.eval_libc_i32("EFD_SEMAPHORE"); - if flags & (efd_cloexec | efd_nonblock | efd_semaphore) != flags { - throw_unsup_format!("eventfd: flag {flags:#x} is unsupported"); + if flags & efd_semaphore == efd_semaphore { + throw_unsup_format!("eventfd: EFD_SEMAPHORE is unsupported"); } + + let mut is_nonblock = false; + // Unset the flag that we support. + // After unloading, flags != 0 means other flags are used. if flags & efd_cloexec == efd_cloexec { - // cloexec does nothing as we don't support `exec` + // cloexec is ignored because Miri does not support exec. + flags &= !efd_cloexec; } if flags & efd_nonblock == efd_nonblock { - // FIXME remember the nonblock flag + flags &= !efd_nonblock; + is_nonblock = true; } - if flags & efd_semaphore == efd_semaphore { - throw_unsup_format!("eventfd: EFD_SEMAPHORE is unsupported"); + if flags != 0 { + throw_unsup_format!("eventfd: encountered unknown unsupported flags {:#x}", flags); } - let fd = this.machine.fds.insert_fd(FileDescriptor::new(Event { val: val.into() })); + let fd = this.machine.fds.insert_fd(FileDescriptor::new(Event { + counter: val.into(), + is_nonblock, + clock: VClock::default(), + })); Ok(Scalar::from_i32(fd)) } } 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 7d0c8be1eaa..e31d43d9190 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -20,8 +20,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs index 5f5d2b0c739..c430eff0180 100644 --- a/src/tools/miri/src/shims/unix/linux/mem.rs +++ b/src/tools/miri/src/shims/unix/linux/mem.rs @@ -8,11 +8,11 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn mremap( &mut self, - old_address: &OpTy<'tcx, Provenance>, - old_size: &OpTy<'tcx, Provenance>, - new_size: &OpTy<'tcx, Provenance>, - flags: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + old_address: &OpTy<'tcx>, + old_size: &OpTy<'tcx>, + new_size: &OpTy<'tcx>, + flags: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let old_address = this.read_pointer(old_address)?; diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs index de83a358db9..bd212039074 100644 --- a/src/tools/miri/src/shims/unix/linux/sync.rs +++ b/src/tools/miri/src/shims/unix/linux/sync.rs @@ -1,13 +1,11 @@ -use std::time::SystemTime; - use crate::*; /// Implementation of the SYS_futex syscall. /// `args` is the arguments *after* the syscall number. pub fn futex<'tcx>( this: &mut MiriInterpCx<'tcx>, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { // The amount of arguments used depends on the type of futex operation. // The full futex syscall takes six arguments (excluding the syscall @@ -84,15 +82,9 @@ pub fn futex<'tcx>( } let timeout = this.deref_pointer_as(&args[3], this.libc_ty_layout("timespec"))?; - let timeout_time = if this.ptr_is_null(timeout.ptr())? { + let timeout = if this.ptr_is_null(timeout.ptr())? { None } else { - let realtime = op & futex_realtime == futex_realtime; - if realtime { - this.check_no_isolation( - "`futex` syscall with `op=FUTEX_WAIT` and non-null timeout with `FUTEX_CLOCK_REALTIME`", - )?; - } let duration = match this.read_timespec(&timeout)? { Some(duration) => duration, None => { @@ -102,23 +94,22 @@ pub fn futex<'tcx>( return Ok(()); } }; - Some(if wait_bitset { + let timeout_clock = if op & futex_realtime == futex_realtime { + this.check_no_isolation( + "`futex` syscall with `op=FUTEX_WAIT` and non-null timeout with `FUTEX_CLOCK_REALTIME`", + )?; + TimeoutClock::RealTime + } else { + TimeoutClock::Monotonic + }; + let timeout_anchor = if wait_bitset { // FUTEX_WAIT_BITSET uses an absolute timestamp. - if realtime { - Timeout::RealTime(SystemTime::UNIX_EPOCH.checked_add(duration).unwrap()) - } else { - Timeout::Monotonic( - this.machine.clock.anchor().checked_add(duration).unwrap(), - ) - } + TimeoutAnchor::Absolute } else { // FUTEX_WAIT uses a relative timestamp. - if realtime { - Timeout::RealTime(SystemTime::now().checked_add(duration).unwrap()) - } else { - Timeout::Monotonic(this.machine.clock.now().checked_add(duration).unwrap()) - } - }) + TimeoutAnchor::Relative + }; + Some((timeout_clock, timeout_anchor, duration)) }; // There may be a concurrent thread changing the value of addr // and then invoking the FUTEX_WAKE syscall. It is critical that the @@ -172,7 +163,7 @@ pub fn futex<'tcx>( this.futex_wait( addr_usize, bitset, - timeout_time, + timeout, Scalar::from_target_isize(0, this), // retval_succ Scalar::from_target_isize(-1, this), // retval_timeout dest.clone(), diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index a1e9ccec676..25002f0a611 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -14,8 +14,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs index 4d727c0b180..de5a5d0759c 100644 --- a/src/tools/miri/src/shims/unix/mem.rs +++ b/src/tools/miri/src/shims/unix/mem.rs @@ -21,13 +21,13 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn mmap( &mut self, - addr: &OpTy<'tcx, Provenance>, - length: &OpTy<'tcx, Provenance>, - prot: &OpTy<'tcx, Provenance>, - flags: &OpTy<'tcx, Provenance>, - fd: &OpTy<'tcx, Provenance>, + addr: &OpTy<'tcx>, + length: &OpTy<'tcx>, + prot: &OpTy<'tcx>, + flags: &OpTy<'tcx>, + fd: &OpTy<'tcx>, offset: i128, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); // We do not support MAP_FIXED, so the addr argument is always ignored (except for the MacOS hack) @@ -123,11 +123,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_pointer(ptr, this)) } - fn munmap( - &mut self, - addr: &OpTy<'tcx, Provenance>, - length: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + fn munmap(&mut self, addr: &OpTy<'tcx>, length: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let addr = this.read_pointer(addr)?; diff --git a/src/tools/miri/src/shims/unix/socket.rs b/src/tools/miri/src/shims/unix/socket.rs index a0fa3bcee34..97bf6348f0b 100644 --- a/src/tools/miri/src/shims/unix/socket.rs +++ b/src/tools/miri/src/shims/unix/socket.rs @@ -35,11 +35,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// <https://linux.die.net/man/2/socketpair> fn socketpair( &mut self, - domain: &OpTy<'tcx, Provenance>, - type_: &OpTy<'tcx, Provenance>, - protocol: &OpTy<'tcx, Provenance>, - sv: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + domain: &OpTy<'tcx>, + type_: &OpTy<'tcx>, + protocol: &OpTy<'tcx>, + sv: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let _domain = this.read_scalar(domain)?.to_i32()?; @@ -51,9 +51,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let fds = &mut this.machine.fds; let sv0 = fds.insert_fd(FileDescriptor::new(SocketPair)); - let sv0 = Scalar::try_from_int(sv0, sv.layout.size).unwrap(); + let sv0 = Scalar::from_int(sv0, sv.layout.size); let sv1 = fds.insert_fd(FileDescriptor::new(SocketPair)); - let sv1 = Scalar::try_from_int(sv1, sv.layout.size).unwrap(); + let sv1 = Scalar::from_int(sv1, sv.layout.size); this.write_scalar(sv0, &sv)?; this.write_scalar(sv1, &sv.offset(sv.layout.size, sv.layout, 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 38cd83edd24..a0cc4a62bfd 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -14,8 +14,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); match link_name.as_str() { @@ -69,6 +69,36 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } + "pset_info" => { + let [pset, tpe, cpus, list] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + // We do not need to handle the current process cpu mask, available_parallelism + // implementation pass null anyway. We only care for the number of + // cpus. + // https://docs.oracle.com/cd/E88353_01/html/E37841/pset-info-2.html + + let pset = this.read_scalar(pset)?.to_i32()?; + let tpe = this.read_pointer(tpe)?; + let list = this.read_pointer(list)?; + + let ps_myid = this.eval_libc_i32("PS_MYID"); + if ps_myid != pset { + throw_unsup_format!("pset_info is only supported with pset==PS_MYID"); + } + + if !this.ptr_is_null(tpe)? { + throw_unsup_format!("pset_info is only supported with type==NULL"); + } + + if !this.ptr_is_null(list)? { + throw_unsup_format!("pset_info is only supported with list==NULL"); + } + + let cpus = this.deref_pointer(cpus)?; + this.write_scalar(Scalar::from_u32(this.machine.num_cpus), &cpus)?; + this.write_null(dest)?; + } + _ => return Ok(EmulateItemResult::NotSupported), } Ok(EmulateItemResult::NeedsReturn) diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs index 0743ad14495..be6732b1b67 100644 --- a/src/tools/miri/src/shims/unix/sync.rs +++ b/src/tools/miri/src/shims/unix/sync.rs @@ -1,5 +1,4 @@ use std::sync::atomic::{AtomicBool, Ordering}; -use std::time::SystemTime; use rustc_target::abi::Size; @@ -10,9 +9,7 @@ use crate::*; // - kind: i32 #[inline] -fn mutexattr_kind_offset<'tcx>( - ecx: &MiriInterpCx<'tcx>, -) -> InterpResult<'tcx, u64> { +fn mutexattr_kind_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { Ok(match &*ecx.tcx.sess.target.os { "linux" | "illumos" | "solaris" | "macos" => 0, os => throw_unsup_format!("`pthread_mutexattr` is not supported on {os}"), @@ -21,7 +18,7 @@ fn mutexattr_kind_offset<'tcx>( fn mutexattr_get_kind<'tcx>( ecx: &MiriInterpCx<'tcx>, - attr_op: &OpTy<'tcx, Provenance>, + attr_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { ecx.deref_pointer_and_read( attr_op, @@ -34,7 +31,7 @@ fn mutexattr_get_kind<'tcx>( fn mutexattr_set_kind<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - attr_op: &OpTy<'tcx, Provenance>, + attr_op: &OpTy<'tcx>, kind: i32, ) -> InterpResult<'tcx, ()> { ecx.deref_pointer_and_write( @@ -53,17 +50,11 @@ fn mutexattr_set_kind<'tcx>( /// in `pthread_mutexattr_settype` function. const PTHREAD_MUTEX_NORMAL_FLAG: i32 = 0x8000000; -fn is_mutex_kind_default<'tcx>( - ecx: &MiriInterpCx<'tcx>, - kind: i32, -) -> InterpResult<'tcx, bool> { +fn is_mutex_kind_default<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tcx, bool> { Ok(kind == ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")) } -fn is_mutex_kind_normal<'tcx>( - ecx: &MiriInterpCx<'tcx>, - kind: i32, -) -> InterpResult<'tcx, bool> { +fn is_mutex_kind_normal<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tcx, bool> { let mutex_normal_kind = ecx.eval_libc_i32("PTHREAD_MUTEX_NORMAL"); Ok(kind == (mutex_normal_kind | PTHREAD_MUTEX_NORMAL_FLAG)) } @@ -125,7 +116,7 @@ fn mutex_kind_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> u64 { fn mutex_get_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - mutex_op: &OpTy<'tcx, Provenance>, + mutex_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, MutexId> { ecx.mutex_get_or_create_id( mutex_op, @@ -136,7 +127,7 @@ fn mutex_get_id<'tcx>( fn mutex_reset_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - mutex_op: &OpTy<'tcx, Provenance>, + mutex_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, ()> { ecx.deref_pointer_and_write( mutex_op, @@ -149,7 +140,7 @@ fn mutex_reset_id<'tcx>( fn mutex_get_kind<'tcx>( ecx: &MiriInterpCx<'tcx>, - mutex_op: &OpTy<'tcx, Provenance>, + mutex_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { ecx.deref_pointer_and_read( mutex_op, @@ -162,7 +153,7 @@ fn mutex_get_kind<'tcx>( fn mutex_set_kind<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - mutex_op: &OpTy<'tcx, Provenance>, + mutex_op: &OpTy<'tcx>, kind: i32, ) -> InterpResult<'tcx, ()> { ecx.deref_pointer_and_write( @@ -206,7 +197,7 @@ fn rwlock_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { fn rwlock_get_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - rwlock_op: &OpTy<'tcx, Provenance>, + rwlock_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, RwLockId> { ecx.rwlock_get_or_create_id( rwlock_op, @@ -220,9 +211,7 @@ fn rwlock_get_id<'tcx>( // - clock: i32 #[inline] -fn condattr_clock_offset<'tcx>( - ecx: &MiriInterpCx<'tcx>, -) -> InterpResult<'tcx, u64> { +fn condattr_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { Ok(match &*ecx.tcx.sess.target.os { "linux" | "illumos" | "solaris" => 0, // macOS does not have a clock attribute. @@ -232,7 +221,7 @@ fn condattr_clock_offset<'tcx>( fn condattr_get_clock_id<'tcx>( ecx: &MiriInterpCx<'tcx>, - attr_op: &OpTy<'tcx, Provenance>, + attr_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { ecx.deref_pointer_and_read( attr_op, @@ -245,7 +234,7 @@ fn condattr_get_clock_id<'tcx>( fn condattr_set_clock_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - attr_op: &OpTy<'tcx, Provenance>, + attr_op: &OpTy<'tcx>, clock_id: i32, ) -> InterpResult<'tcx, ()> { ecx.deref_pointer_and_write( @@ -323,7 +312,7 @@ fn cond_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> u64 { fn cond_get_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - cond_op: &OpTy<'tcx, Provenance>, + cond_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, CondvarId> { ecx.condvar_get_or_create_id( cond_op, @@ -334,7 +323,7 @@ fn cond_get_id<'tcx>( fn cond_reset_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - cond_op: &OpTy<'tcx, Provenance>, + cond_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, ()> { ecx.deref_pointer_and_write( cond_op, @@ -347,7 +336,7 @@ fn cond_reset_id<'tcx>( fn cond_get_clock_id<'tcx>( ecx: &MiriInterpCx<'tcx>, - cond_op: &OpTy<'tcx, Provenance>, + cond_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { ecx.deref_pointer_and_read( cond_op, @@ -360,7 +349,7 @@ fn cond_get_clock_id<'tcx>( fn cond_set_clock_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - cond_op: &OpTy<'tcx, Provenance>, + cond_op: &OpTy<'tcx>, clock_id: i32, ) -> InterpResult<'tcx, ()> { ecx.deref_pointer_and_write( @@ -374,10 +363,7 @@ fn cond_set_clock_id<'tcx>( impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn pthread_mutexattr_init( - &mut self, - attr_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_mutexattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let default_kind = this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT"); @@ -388,8 +374,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_mutexattr_settype( &mut self, - attr_op: &OpTy<'tcx, Provenance>, - kind_op: &OpTy<'tcx, Provenance>, + attr_op: &OpTy<'tcx>, + kind_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -427,10 +413,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(0) } - fn pthread_mutexattr_destroy( - &mut self, - attr_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_mutexattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); // Destroying an uninit pthread_mutexattr is UB, so check to make sure it's not uninit. @@ -457,8 +440,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_mutex_init( &mut self, - mutex_op: &OpTy<'tcx, Provenance>, - attr_op: &OpTy<'tcx, Provenance>, + mutex_op: &OpTy<'tcx>, + attr_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -479,8 +462,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_mutex_lock( &mut self, - mutex_op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + mutex_op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -518,10 +501,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn pthread_mutex_trylock( - &mut self, - mutex_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?; @@ -553,10 +533,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn pthread_mutex_unlock( - &mut self, - mutex_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?; @@ -587,10 +564,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn pthread_mutex_destroy( - &mut self, - mutex_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_mutex_destroy(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = mutex_get_id(this, mutex_op)?; @@ -614,8 +588,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_rwlock_rdlock( &mut self, - rwlock_op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + rwlock_op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -631,10 +605,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn pthread_rwlock_tryrdlock( - &mut self, - rwlock_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_id(this, rwlock_op)?; @@ -649,8 +620,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_rwlock_wrlock( &mut self, - rwlock_op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + rwlock_op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -678,10 +649,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn pthread_rwlock_trywrlock( - &mut self, - rwlock_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_trywrlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_id(this, rwlock_op)?; @@ -694,10 +662,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn pthread_rwlock_unlock( - &mut self, - rwlock_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_unlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_id(this, rwlock_op)?; @@ -712,10 +677,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn pthread_rwlock_destroy( - &mut self, - rwlock_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_destroy(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_id(this, rwlock_op)?; @@ -736,10 +698,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(0) } - fn pthread_condattr_init( - &mut self, - attr_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_condattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); // no clock attribute on macOS @@ -756,9 +715,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_condattr_setclock( &mut self, - attr_op: &OpTy<'tcx, Provenance>, - clock_id_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + attr_op: &OpTy<'tcx>, + clock_id_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let clock_id = this.read_scalar(clock_id_op)?.to_i32()?; @@ -776,9 +735,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_condattr_getclock( &mut self, - attr_op: &OpTy<'tcx, Provenance>, - clk_id_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + attr_op: &OpTy<'tcx>, + clk_id_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let clock_id = condattr_get_clock_id(this, attr_op)?; @@ -787,10 +746,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_i32(0)) } - fn pthread_condattr_destroy( - &mut self, - attr_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); // Destroying an uninit pthread_condattr is UB, so check to make sure it's not uninit. @@ -810,8 +766,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_cond_init( &mut self, - cond_op: &OpTy<'tcx, Provenance>, - attr_op: &OpTy<'tcx, Provenance>, + cond_op: &OpTy<'tcx>, + attr_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -831,17 +787,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(0) } - fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_id(this, cond_op)?; this.condvar_signal(id)?; Ok(0) } - fn pthread_cond_broadcast( - &mut self, - cond_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_cond_broadcast(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_id(this, cond_op)?; while this.condvar_signal(id)? {} @@ -850,9 +803,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_cond_wait( &mut self, - cond_op: &OpTy<'tcx, Provenance>, - mutex_op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + cond_op: &OpTy<'tcx>, + mutex_op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -873,10 +826,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_cond_timedwait( &mut self, - cond_op: &OpTy<'tcx, Provenance>, - mutex_op: &OpTy<'tcx, Provenance>, - abstime_op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + cond_op: &OpTy<'tcx>, + mutex_op: &OpTy<'tcx>, + abstime_op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -895,11 +848,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return Ok(()); } }; - let timeout_time = if is_cond_clock_realtime(this, clock_id) { + let timeout_clock = if is_cond_clock_realtime(this, clock_id) { this.check_no_isolation("`pthread_cond_timedwait` with `CLOCK_REALTIME`")?; - Timeout::RealTime(SystemTime::UNIX_EPOCH.checked_add(duration).unwrap()) + TimeoutClock::RealTime } else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC") { - Timeout::Monotonic(this.machine.clock.anchor().checked_add(duration).unwrap()) + TimeoutClock::Monotonic } else { throw_unsup_format!("unsupported clock id: {}", clock_id); }; @@ -907,7 +860,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.condvar_wait( id, mutex_id, - Some(timeout_time), + Some((timeout_clock, TimeoutAnchor::Absolute, duration)), Scalar::from_i32(0), this.eval_libc("ETIMEDOUT"), // retval_timeout dest.clone(), @@ -916,10 +869,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn pthread_cond_destroy( - &mut self, - cond_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_id(this, cond_op)?; diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs index 323b5c1992e..6fe331ba623 100644 --- a/src/tools/miri/src/shims/unix/thread.rs +++ b/src/tools/miri/src/shims/unix/thread.rs @@ -6,10 +6,10 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_create( &mut self, - thread: &OpTy<'tcx, Provenance>, - _attr: &OpTy<'tcx, Provenance>, - start_routine: &OpTy<'tcx, Provenance>, - arg: &OpTy<'tcx, Provenance>, + thread: &OpTy<'tcx>, + _attr: &OpTy<'tcx>, + start_routine: &OpTy<'tcx>, + arg: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -32,8 +32,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_join( &mut self, - thread: &OpTy<'tcx, Provenance>, - retval: &OpTy<'tcx, Provenance>, + thread: &OpTy<'tcx>, + retval: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -48,7 +48,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(0) } - fn pthread_detach(&mut self, thread: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let thread_id = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?; @@ -60,7 +60,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(0) } - fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar<Provenance>> { + fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let thread_id = this.active_thread(); @@ -71,10 +71,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// including the null terminator. fn pthread_setname_np( &mut self, - thread: Scalar<Provenance>, - name: Scalar<Provenance>, + thread: Scalar, + name: Scalar, max_name_len: usize, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let thread = thread.to_int(this.libc_ty_layout("pthread_t").size)?; @@ -95,10 +95,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_getname_np( &mut self, - thread: Scalar<Provenance>, - name_out: Scalar<Provenance>, - len: Scalar<Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + thread: Scalar, + name_out: Scalar, + len: Scalar, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let thread = thread.to_int(this.libc_ty_layout("pthread_t").size)?; diff --git a/src/tools/miri/src/shims/wasi/foreign_items.rs b/src/tools/miri/src/shims/wasi/foreign_items.rs index b81b35bd963..e9fe90081d0 100644 --- a/src/tools/miri/src/shims/wasi/foreign_items.rs +++ b/src/tools/miri/src/shims/wasi/foreign_items.rs @@ -14,8 +14,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); match link_name.as_str() { diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs index 488a05366d2..ed3eb697986 100644 --- a/src/tools/miri/src/shims/windows/env.rs +++ b/src/tools/miri/src/shims/windows/env.rs @@ -38,10 +38,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(non_snake_case)] fn GetEnvironmentVariableW( &mut self, - name_op: &OpTy<'tcx, Provenance>, // LPCWSTR - buf_op: &OpTy<'tcx, Provenance>, // LPWSTR - size_op: &OpTy<'tcx, Provenance>, // DWORD - ) -> InterpResult<'tcx, Scalar<Provenance>> { + name_op: &OpTy<'tcx>, // LPCWSTR + buf_op: &OpTy<'tcx>, // LPWSTR + size_op: &OpTy<'tcx>, // DWORD + ) -> InterpResult<'tcx, Scalar> { // ^ Returns DWORD (u32 on Windows) let this = self.eval_context_mut(); @@ -71,7 +71,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } #[allow(non_snake_case)] - fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Pointer<Option<Provenance>>> { + fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentStringsW"); @@ -93,10 +93,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } #[allow(non_snake_case)] - fn FreeEnvironmentStringsW( - &mut self, - env_block_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + fn FreeEnvironmentStringsW(&mut self, env_block_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("windows", "FreeEnvironmentStringsW"); @@ -109,9 +106,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(non_snake_case)] fn SetEnvironmentVariableW( &mut self, - name_op: &OpTy<'tcx, Provenance>, // LPCWSTR - value_op: &OpTy<'tcx, Provenance>, // LPCWSTR - ) -> InterpResult<'tcx, Scalar<Provenance>> { + name_op: &OpTy<'tcx>, // LPCWSTR + value_op: &OpTy<'tcx>, // LPCWSTR + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("windows", "SetEnvironmentVariableW"); @@ -142,9 +139,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(non_snake_case)] fn GetCurrentDirectoryW( &mut self, - size_op: &OpTy<'tcx, Provenance>, // DWORD - buf_op: &OpTy<'tcx, Provenance>, // LPTSTR - ) -> InterpResult<'tcx, Scalar<Provenance>> { + size_op: &OpTy<'tcx>, // DWORD + buf_op: &OpTy<'tcx>, // LPTSTR + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetCurrentDirectoryW"); @@ -174,8 +171,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(non_snake_case)] fn SetCurrentDirectoryW( &mut self, - path_op: &OpTy<'tcx, Provenance>, // LPCTSTR - ) -> InterpResult<'tcx, Scalar<Provenance>> { + path_op: &OpTy<'tcx>, // LPCTSTR + ) -> InterpResult<'tcx, Scalar> { // ^ Returns BOOL (i32 on Windows) let this = self.eval_context_mut(); @@ -211,10 +208,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(non_snake_case)] fn GetUserProfileDirectoryW( &mut self, - token: &OpTy<'tcx, Provenance>, // HANDLE - buf: &OpTy<'tcx, Provenance>, // LPWSTR - size: &OpTy<'tcx, Provenance>, // LPDWORD - ) -> InterpResult<'tcx, Scalar<Provenance>> // returns BOOL + token: &OpTy<'tcx>, // HANDLE + buf: &OpTy<'tcx>, // LPWSTR + size: &OpTy<'tcx>, // LPDWORD + ) -> InterpResult<'tcx, Scalar> // returns BOOL { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetUserProfileDirectoryW"); diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index a60c2a337cf..bfa14bcb5fa 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -82,8 +82,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs index 3e274a5b802..58c8683ff27 100644 --- a/src/tools/miri/src/shims/windows/handle.rs +++ b/src/tools/miri/src/shims/windows/handle.rs @@ -119,7 +119,7 @@ impl Handle { Self::new(discriminant, data) } - pub fn to_scalar(self, cx: &impl HasDataLayout) -> Scalar<Provenance> { + pub fn to_scalar(self, cx: &impl HasDataLayout) -> Scalar { // 64-bit handles are sign extended 32-bit handles // see https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication #[allow(clippy::cast_possible_wrap)] // we want it to wrap @@ -128,7 +128,7 @@ impl Handle { } pub fn from_scalar<'tcx>( - handle: Scalar<Provenance>, + handle: Scalar, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Option<Self>> { let sign_extended_handle = handle.to_target_isize(cx)?; @@ -155,7 +155,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ))) } - fn CloseHandle(&mut self, handle_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn CloseHandle(&mut self, handle_op: &OpTy<'tcx>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let handle = this.read_scalar(handle_op)?; diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs index d5fe15b401b..e1fbb77037c 100644 --- a/src/tools/miri/src/shims/windows/sync.rs +++ b/src/tools/miri/src/shims/windows/sync.rs @@ -10,10 +10,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Windows sync primitives are pointer sized. // We only use the first 4 bytes for the id. - fn init_once_get_id( - &mut self, - init_once_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, InitOnceId> { + fn init_once_get_id(&mut self, init_once_op: &OpTy<'tcx>) -> InterpResult<'tcx, InitOnceId> { let this = self.eval_context_mut(); this.init_once_get_or_create_id(init_once_op, this.windows_ty_layout("INIT_ONCE"), 0) } @@ -22,8 +19,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { fn init_once_try_begin( &mut self, id: InitOnceId, - pending_place: &MPlaceTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + pending_place: &MPlaceTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); Ok(match this.init_once_status(id) { @@ -49,11 +46,11 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn InitOnceBeginInitialize( &mut self, - init_once_op: &OpTy<'tcx, Provenance>, - flags_op: &OpTy<'tcx, Provenance>, - pending_op: &OpTy<'tcx, Provenance>, - context_op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + init_once_op: &OpTy<'tcx>, + flags_op: &OpTy<'tcx>, + pending_op: &OpTy<'tcx>, + context_op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -82,8 +79,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { callback!( @capture<'tcx> { id: InitOnceId, - pending_place: MPlaceTy<'tcx, Provenance>, - dest: MPlaceTy<'tcx, Provenance>, + pending_place: MPlaceTy<'tcx>, + dest: MPlaceTy<'tcx>, } @unblock = |this| { let ret = this.init_once_try_begin(id, &pending_place, &dest)?; @@ -97,10 +94,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn InitOnceComplete( &mut self, - init_once_op: &OpTy<'tcx, Provenance>, - flags_op: &OpTy<'tcx, Provenance>, - context_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { + init_once_op: &OpTy<'tcx>, + flags_op: &OpTy<'tcx>, + context_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let id = this.init_once_get_id(init_once_op)?; @@ -137,11 +134,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn WaitOnAddress( &mut self, - ptr_op: &OpTy<'tcx, Provenance>, - compare_op: &OpTy<'tcx, Provenance>, - size_op: &OpTy<'tcx, Provenance>, - timeout_op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + ptr_op: &OpTy<'tcx>, + compare_op: &OpTy<'tcx>, + size_op: &OpTy<'tcx>, + timeout_op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -160,11 +157,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; let size = Size::from_bytes(size); - let timeout_time = if timeout_ms == this.eval_windows_u32("c", "INFINITE") { + let timeout = if timeout_ms == this.eval_windows_u32("c", "INFINITE") { None } else { let duration = Duration::from_millis(timeout_ms.into()); - Some(Timeout::Monotonic(this.machine.clock.now().checked_add(duration).unwrap())) + Some((TimeoutClock::Monotonic, TimeoutAnchor::Relative, duration)) }; // See the Linux futex implementation for why this fence exists. @@ -180,7 +177,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.futex_wait( addr, u32::MAX, // bitset - timeout_time, + timeout, Scalar::from_i32(1), // retval_succ Scalar::from_i32(0), // retval_timeout dest.clone(), @@ -193,7 +190,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn WakeByAddressSingle(&mut self, ptr_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn WakeByAddressSingle(&mut self, ptr_op: &OpTy<'tcx>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let ptr = this.read_pointer(ptr_op)?; @@ -206,7 +203,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn WakeByAddressAll(&mut self, ptr_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn WakeByAddressAll(&mut self, ptr_op: &OpTy<'tcx>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let ptr = this.read_pointer(ptr_op)?; diff --git a/src/tools/miri/src/shims/windows/thread.rs b/src/tools/miri/src/shims/windows/thread.rs index a9ef03d14ae..f3ddf6072af 100644 --- a/src/tools/miri/src/shims/windows/thread.rs +++ b/src/tools/miri/src/shims/windows/thread.rs @@ -10,12 +10,12 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn CreateThread( &mut self, - security_op: &OpTy<'tcx, Provenance>, - stacksize_op: &OpTy<'tcx, Provenance>, - start_op: &OpTy<'tcx, Provenance>, - arg_op: &OpTy<'tcx, Provenance>, - flags_op: &OpTy<'tcx, Provenance>, - thread_op: &OpTy<'tcx, Provenance>, + security_op: &OpTy<'tcx>, + stacksize_op: &OpTy<'tcx>, + start_op: &OpTy<'tcx>, + arg_op: &OpTy<'tcx>, + flags_op: &OpTy<'tcx>, + thread_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); @@ -57,8 +57,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn WaitForSingleObject( &mut self, - handle_op: &OpTy<'tcx, Provenance>, - timeout_op: &OpTy<'tcx, Provenance>, + handle_op: &OpTy<'tcx>, + timeout_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, u32> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/x86/aesni.rs b/src/tools/miri/src/shims/x86/aesni.rs index c1be1d4582a..e4e1531157a 100644 --- a/src/tools/miri/src/shims/x86/aesni.rs +++ b/src/tools/miri/src/shims/x86/aesni.rs @@ -6,15 +6,13 @@ use rustc_target::spec::abi::Abi; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExt<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_aesni_intrinsic( &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); this.expect_target_feature_for_intrinsic(link_name, "aes")?; @@ -135,9 +133,9 @@ pub(super) trait EvalContextExt<'tcx>: // `state` with the corresponding 128-bit key of `key`. fn aes_round<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - state: &OpTy<'tcx, Provenance>, - key: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + state: &OpTy<'tcx>, + key: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, f: impl Fn(u128, u128) -> u128, ) -> InterpResult<'tcx, ()> { assert_eq!(dest.layout.size, state.layout.size); diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs index f782fbfff4e..07d737e0663 100644 --- a/src/tools/miri/src/shims/x86/avx.rs +++ b/src/tools/miri/src/shims/x86/avx.rs @@ -13,15 +13,13 @@ use super::{ use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExt<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_avx_intrinsic( &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); this.expect_target_feature_for_intrinsic(link_name, "avx")?; diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs index 91764a20572..016c525e57b 100644 --- a/src/tools/miri/src/shims/x86/avx2.rs +++ b/src/tools/miri/src/shims/x86/avx2.rs @@ -11,15 +11,13 @@ use super::{ use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExt<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_avx2_intrinsic( &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); this.expect_target_feature_for_intrinsic(link_name, "avx2")?; diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index b5951e9e895..f2d120df21c 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -26,8 +26,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); // Prefix should have already been checked. @@ -105,6 +105,13 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } + "pclmulqdq" => { + let [left, right, imm] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + pclmulqdq(this, left, right, imm, dest)?; + } + name if name.starts_with("sse.") => { return sse::EvalContextExt::emulate_x86_sse_intrinsic( this, link_name, abi, args, dest, @@ -244,9 +251,9 @@ impl FloatBinOp { fn bin_op_float<'tcx, F: rustc_apfloat::Float>( this: &crate::MiriInterpCx<'tcx>, which: FloatBinOp, - left: &ImmTy<'tcx, Provenance>, - right: &ImmTy<'tcx, Provenance>, -) -> InterpResult<'tcx, Scalar<Provenance>> { + left: &ImmTy<'tcx>, + right: &ImmTy<'tcx>, +) -> InterpResult<'tcx, Scalar> { match which { FloatBinOp::Arith(which) => { let res = this.binary_op(which, left, right)?; @@ -306,9 +313,9 @@ fn bin_op_float<'tcx, F: rustc_apfloat::Float>( fn bin_op_simd_float_first<'tcx, F: rustc_apfloat::Float>( this: &mut crate::MiriInterpCx<'tcx>, which: FloatBinOp, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -337,9 +344,9 @@ fn bin_op_simd_float_first<'tcx, F: rustc_apfloat::Float>( fn bin_op_simd_float_all<'tcx, F: rustc_apfloat::Float>( this: &mut crate::MiriInterpCx<'tcx>, which: FloatBinOp, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -384,8 +391,8 @@ enum FloatUnaryOp { fn unary_op_f32<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, which: FloatUnaryOp, - op: &ImmTy<'tcx, Provenance>, -) -> InterpResult<'tcx, Scalar<Provenance>> { + op: &ImmTy<'tcx>, +) -> InterpResult<'tcx, Scalar> { match which { FloatUnaryOp::Sqrt => { let op = op.to_scalar(); @@ -435,8 +442,8 @@ fn apply_random_float_error<F: rustc_apfloat::Float>( fn unary_op_ss<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, which: FloatUnaryOp, - op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.mplace_to_simd(dest)?; @@ -458,8 +465,8 @@ fn unary_op_ss<'tcx>( fn unary_op_ps<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, which: FloatUnaryOp, - op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.mplace_to_simd(dest)?; @@ -494,10 +501,10 @@ enum ShiftOp { /// bit is copied to all bits. fn shift_simd_by_scalar<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, which: ShiftOp, - dest: &MPlaceTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (left, left_len) = this.operand_to_simd(left)?; let (dest, dest_len) = this.mplace_to_simd(dest)?; @@ -550,10 +557,10 @@ fn shift_simd_by_scalar<'tcx>( /// bit is copied to all bits. fn shift_simd_by_simd<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, which: ShiftOp, - dest: &MPlaceTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -602,7 +609,7 @@ fn shift_simd_by_simd<'tcx>( /// the first value. fn extract_first_u64<'tcx>( this: &crate::MiriInterpCx<'tcx>, - op: &OpTy<'tcx, Provenance>, + op: &OpTy<'tcx>, ) -> InterpResult<'tcx, u64> { // Transmute vector to `[u64; 2]` let array_layout = this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u64, 2))?; @@ -616,10 +623,10 @@ fn extract_first_u64<'tcx>( // and copies the remaining elements from `left`. fn round_first<'tcx, F: rustc_apfloat::Float>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - rounding: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + rounding: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -647,9 +654,9 @@ fn round_first<'tcx, F: rustc_apfloat::Float>( // Rounds all elements of `op` according to `rounding`. fn round_all<'tcx, F: rustc_apfloat::Float>( this: &mut crate::MiriInterpCx<'tcx>, - op: &OpTy<'tcx, Provenance>, - rounding: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + op: &OpTy<'tcx>, + rounding: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.mplace_to_simd(dest)?; @@ -699,9 +706,9 @@ fn rounding_from_imm<'tcx>(rounding: i32) -> InterpResult<'tcx, rustc_apfloat::R /// has less elements than `dest`, the rest is filled with zeros. fn convert_float_to_int<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - op: &OpTy<'tcx, Provenance>, + op: &OpTy<'tcx>, rnd: rustc_apfloat::Round, - dest: &MPlaceTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.mplace_to_simd(dest)?; @@ -734,8 +741,8 @@ fn convert_float_to_int<'tcx>( /// will wrap around. fn int_abs<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.mplace_to_simd(dest)?; @@ -802,9 +809,9 @@ fn horizontal_bin_op<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, which: mir::BinOp, saturating: bool, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { assert_eq!(left.layout, dest.layout); assert_eq!(right.layout, dest.layout); @@ -853,10 +860,10 @@ fn horizontal_bin_op<'tcx>( /// 128-bit blocks of `left` and `right`). fn conditional_dot_product<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - imm: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + imm: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { assert_eq!(left.layout, dest.layout); assert_eq!(right.layout, dest.layout); @@ -911,8 +918,8 @@ fn conditional_dot_product<'tcx>( /// The second is true when `(op & mask) == mask` fn test_bits_masked<'tcx>( this: &crate::MiriInterpCx<'tcx>, - op: &OpTy<'tcx, Provenance>, - mask: &OpTy<'tcx, Provenance>, + op: &OpTy<'tcx>, + mask: &OpTy<'tcx>, ) -> InterpResult<'tcx, (bool, bool)> { assert_eq!(op.layout, mask.layout); @@ -942,8 +949,8 @@ fn test_bits_masked<'tcx>( /// The second is true when the highest bit of each element of `!op & mask` is zero. fn test_high_bits_masked<'tcx>( this: &crate::MiriInterpCx<'tcx>, - op: &OpTy<'tcx, Provenance>, - mask: &OpTy<'tcx, Provenance>, + op: &OpTy<'tcx>, + mask: &OpTy<'tcx>, ) -> InterpResult<'tcx, (bool, bool)> { assert_eq!(op.layout, mask.layout); @@ -973,9 +980,9 @@ fn test_high_bits_masked<'tcx>( /// element of `mask`. `ptr` does not need to be aligned. fn mask_load<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - ptr: &OpTy<'tcx, Provenance>, - mask: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + ptr: &OpTy<'tcx>, + mask: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (mask, mask_len) = this.operand_to_simd(mask)?; let (dest, dest_len) = this.mplace_to_simd(dest)?; @@ -1006,9 +1013,9 @@ fn mask_load<'tcx>( /// element of `mask`. `ptr` does not need to be aligned. fn mask_store<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - ptr: &OpTy<'tcx, Provenance>, - mask: &OpTy<'tcx, Provenance>, - value: &OpTy<'tcx, Provenance>, + ptr: &OpTy<'tcx>, + mask: &OpTy<'tcx>, + value: &OpTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (mask, mask_len) = this.operand_to_simd(mask)?; let (value, value_len) = this.operand_to_simd(value)?; @@ -1046,10 +1053,10 @@ fn mask_store<'tcx>( /// 128-bit chunks of `left` and `right`). fn mpsadbw<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - imm: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + imm: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { assert_eq!(left.layout, right.layout); assert_eq!(left.layout.size, dest.layout.size); @@ -1103,9 +1110,9 @@ fn mpsadbw<'tcx>( /// <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mulhrs_epi16> fn pmulhrsw<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -1133,6 +1140,68 @@ fn pmulhrsw<'tcx>( Ok(()) } +/// Perform a carry-less multiplication of two 64-bit integers, selected from `left` and `right` according to `imm8`, +/// and store the results in `dst`. +/// +/// `left` and `right` are both vectors of type 2 x i64. Only bits 0 and 4 of `imm8` matter; +/// they select the element of `left` and `right`, respectively. +/// +/// <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_clmulepi64_si128> +fn pclmulqdq<'tcx>( + this: &mut MiriInterpCx<'tcx>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + imm8: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, +) -> InterpResult<'tcx, ()> { + assert_eq!(left.layout, right.layout); + assert_eq!(left.layout.size, dest.layout.size); + + // Transmute to `[u64; 2]` + + let array_layout = this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u64, 2))?; + let left = left.transmute(array_layout, this)?; + let right = right.transmute(array_layout, this)?; + let dest = dest.transmute(array_layout, this)?; + + let imm8 = this.read_scalar(imm8)?.to_u8()?; + + // select the 64-bit integer from left that the user specified (low or high) + let index = if (imm8 & 0x01) == 0 { 0 } else { 1 }; + let left = this.read_scalar(&this.project_index(&left, index)?)?.to_u64()?; + + // select the 64-bit integer from right that the user specified (low or high) + let index = if (imm8 & 0x10) == 0 { 0 } else { 1 }; + let right = this.read_scalar(&this.project_index(&right, index)?)?.to_u64()?; + + // Perform carry-less multiplication + // + // This operation is like long multiplication, but ignores all carries. + // That idea corresponds to the xor operator, which is used in the implementation. + // + // Wikipedia has an example https://en.wikipedia.org/wiki/Carry-less_product#Example + let mut result: u128 = 0; + + for i in 0..64 { + // if the i-th bit in right is set + if (right & (1 << i)) != 0 { + // xor result with `left` shifted to the left by i positions + result ^= (left as u128) << i; + } + } + + let result_low = (result & 0xFFFF_FFFF_FFFF_FFFF) as u64; + let result_high = (result >> 64) as u64; + + let dest_low = this.project_index(&dest, 0)?; + this.write_scalar(Scalar::from_u64(result_low), &dest_low)?; + + let dest_high = this.project_index(&dest, 1)?; + this.write_scalar(Scalar::from_u64(result_high), &dest_high)?; + + Ok(()) +} + /// Packs two N-bit integer vectors to a single N/2-bit integers. /// /// The conversion from N-bit to N/2-bit should be provided by `f`. @@ -1142,10 +1211,10 @@ fn pmulhrsw<'tcx>( /// 128-bit chunks of `left` and `right`). fn pack_generic<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, - f: impl Fn(Scalar<Provenance>) -> InterpResult<'tcx, Scalar<Provenance>>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, + f: impl Fn(Scalar) -> InterpResult<'tcx, Scalar>, ) -> InterpResult<'tcx, ()> { assert_eq!(left.layout, right.layout); assert_eq!(left.layout.size, dest.layout.size); @@ -1187,9 +1256,9 @@ fn pack_generic<'tcx>( /// 128-bit chunks of `left` and `right`). fn packsswb<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { pack_generic(this, left, right, dest, |op| { let op = op.to_i16()?; @@ -1206,9 +1275,9 @@ fn packsswb<'tcx>( /// 128-bit chunks of `left` and `right`). fn packuswb<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { pack_generic(this, left, right, dest, |op| { let op = op.to_i16()?; @@ -1225,9 +1294,9 @@ fn packuswb<'tcx>( /// 128-bit chunks of `left` and `right`). fn packssdw<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { pack_generic(this, left, right, dest, |op| { let op = op.to_i32()?; @@ -1244,9 +1313,9 @@ fn packssdw<'tcx>( /// 128-bit chunks of `left` and `right`). fn packusdw<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { pack_generic(this, left, right, dest, |op| { let op = op.to_i32()?; @@ -1261,9 +1330,9 @@ fn packusdw<'tcx>( /// In other words, multiplies `left` with `right.signum()`. fn psign<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs index 0afb2090cad..32e8e8a66c1 100644 --- a/src/tools/miri/src/shims/x86/sse.rs +++ b/src/tools/miri/src/shims/x86/sse.rs @@ -10,15 +10,13 @@ use super::{ use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExt<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_sse_intrinsic( &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); this.expect_target_feature_for_intrinsic(link_name, "sse")?; diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index bdff22cfa95..e10047fefe6 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -9,15 +9,13 @@ use super::{ use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExt<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_sse2_intrinsic( &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); this.expect_target_feature_for_intrinsic(link_name, "sse2")?; diff --git a/src/tools/miri/src/shims/x86/sse3.rs b/src/tools/miri/src/shims/x86/sse3.rs index 7dbe5163199..ef5a55d6eb2 100644 --- a/src/tools/miri/src/shims/x86/sse3.rs +++ b/src/tools/miri/src/shims/x86/sse3.rs @@ -6,15 +6,13 @@ use super::horizontal_bin_op; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExt<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_sse3_intrinsic( &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); this.expect_target_feature_for_intrinsic(link_name, "sse3")?; diff --git a/src/tools/miri/src/shims/x86/sse41.rs b/src/tools/miri/src/shims/x86/sse41.rs index b3880fec3e0..9e048fb9eb8 100644 --- a/src/tools/miri/src/shims/x86/sse41.rs +++ b/src/tools/miri/src/shims/x86/sse41.rs @@ -5,15 +5,13 @@ use super::{conditional_dot_product, mpsadbw, packusdw, round_all, round_first, use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExt<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_sse41_intrinsic( &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); this.expect_target_feature_for_intrinsic(link_name, "sse4.1")?; diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs index 1f7870f8ca0..6a815e4cea3 100644 --- a/src/tools/miri/src/shims/x86/ssse3.rs +++ b/src/tools/miri/src/shims/x86/ssse3.rs @@ -6,15 +6,13 @@ use super::{horizontal_bin_op, int_abs, pmulhrsw, psign}; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExt<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_ssse3_intrinsic( &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); this.expect_target_feature_for_intrinsic(link_name, "ssse3")?; diff --git a/src/tools/miri/test-cargo-miri/Cargo.lock b/src/tools/miri/test-cargo-miri/Cargo.lock index 4783f79ea8f..8f618e7ffb3 100644 --- a/src/tools/miri/test-cargo-miri/Cargo.lock +++ b/src/tools/miri/test-cargo-miri/Cargo.lock @@ -124,6 +124,10 @@ dependencies = [ ] [[package]] +name = "test-local-crate-detection" +version = "0.1.0" + +[[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/src/tools/miri/test-cargo-miri/Cargo.toml b/src/tools/miri/test-cargo-miri/Cargo.toml index bfef388669d..574f1d05a6f 100644 --- a/src/tools/miri/test-cargo-miri/Cargo.toml +++ b/src/tools/miri/test-cargo-miri/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["subcrate", "issue-1567", "exported-symbol-dep"] +members = ["subcrate", "issue-1567", "exported-symbol-dep", "test-local-crate-detection"] exclude = ["no-std-smoke"] # it wants to be panic="abort" [package] diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py index 83f3e4c919b..d855c333a75 100755 --- a/src/tools/miri/test-cargo-miri/run-test.py +++ b/src/tools/miri/test-cargo-miri/run-test.py @@ -131,6 +131,10 @@ def test_cargo_miri_run(): cargo_miri("run") + ["--target-dir=custom-run", "--", "--target-dir=target/custom-run"], "run.args.stdout.ref", "run.custom-target-dir.stderr.ref", ) + test("`cargo miri run --package=test-local-crate-detection` (test local crate detection)", + cargo_miri("run") + ["--package=test-local-crate-detection"], + "run.local_crate.stdout.ref", "run.local_crate.stderr.ref", + ) def test_cargo_miri_test(): # rustdoc is not run on foreign targets diff --git a/src/tools/miri/test-cargo-miri/run.local_crate.stderr.ref b/src/tools/miri/test-cargo-miri/run.local_crate.stderr.ref new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/src/tools/miri/test-cargo-miri/run.local_crate.stderr.ref diff --git a/src/tools/miri/test-cargo-miri/run.local_crate.stdout.ref b/src/tools/miri/test-cargo-miri/run.local_crate.stdout.ref new file mode 100644 index 00000000000..1587de9ff3f --- /dev/null +++ b/src/tools/miri/test-cargo-miri/run.local_crate.stdout.ref @@ -0,0 +1 @@ +subcrate,issue_1567,exported_symbol_dep,test_local_crate_detection,cargo_miri_test,cdylib,exported_symbol,issue_1691,issue_1705,issue_rust_86261,proc_macro_crate diff --git a/src/tools/miri/test-cargo-miri/test-local-crate-detection/Cargo.toml b/src/tools/miri/test-cargo-miri/test-local-crate-detection/Cargo.toml new file mode 100644 index 00000000000..2d41b210d4c --- /dev/null +++ b/src/tools/miri/test-cargo-miri/test-local-crate-detection/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "test-local-crate-detection" +version = "0.1.0" +edition = "2021" diff --git a/src/tools/miri/test-cargo-miri/test-local-crate-detection/src/main.rs b/src/tools/miri/test-cargo-miri/test-local-crate-detection/src/main.rs new file mode 100644 index 00000000000..0991aa38460 --- /dev/null +++ b/src/tools/miri/test-cargo-miri/test-local-crate-detection/src/main.rs @@ -0,0 +1,5 @@ +fn main() { + // Make sure we detect all crates from this workspace as "local". + // The env var is set during the "build" so we can use `env!` to access it directly. + println!("{}", env!("MIRI_LOCAL_CRATES")); +} diff --git a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs new file mode 100644 index 00000000000..fb9a23206c6 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs @@ -0,0 +1,11 @@ +//@only-target-linux +fn main() { + // eventfd read will block when EFD_NONBLOCK flag is clear and counter = 0. + // This will pass when blocking is implemented. + let flags = libc::EFD_CLOEXEC; + let fd = unsafe { libc::eventfd(0, flags) }; + let mut buf: [u8; 8] = [0; 8]; + let _res: i32 = unsafe { + libc::read(fd, buf.as_mut_ptr().cast(), buf.len() as libc::size_t).try_into().unwrap() //~ERROR: blocking is unsupported + }; +} diff --git a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.stderr b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.stderr new file mode 100644 index 00000000000..fdd0b4272ca --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: eventfd: blocking is unsupported + --> $DIR/libc_eventfd_read_block.rs:LL:CC + | +LL | libc::read(fd, buf.as_mut_ptr().cast(), buf.len() as libc::size_t).try_into().unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ eventfd: blocking is unsupported + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = note: BACKTRACE: + = note: inside `main` at $DIR/libc_eventfd_read_block.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/libc_eventfd_write_block.rs b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs new file mode 100644 index 00000000000..2037a516dea --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs @@ -0,0 +1,21 @@ +//@only-target-linux +fn main() { + // eventfd write will block when EFD_NONBLOCK flag is clear + // and the addition caused counter to exceed u64::MAX - 1. + // This will pass when blocking is implemented. + let flags = libc::EFD_CLOEXEC; + let fd = unsafe { libc::eventfd(0, flags) }; + // Write u64 - 1. + let mut sized_8_data: [u8; 8] = (u64::MAX - 1).to_ne_bytes(); + let res: i64 = unsafe { + libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap() + }; + assert_eq!(res, 8); + + // Write 1. + sized_8_data = 1_u64.to_ne_bytes(); + // Write 1 to the counter. + let _res: i64 = unsafe { + libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap() //~ERROR: blocking is unsupported + }; +} diff --git a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.stderr b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.stderr new file mode 100644 index 00000000000..f12c0ddfb17 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: eventfd: blocking is unsupported + --> $DIR/libc_eventfd_write_block.rs:LL:CC + | +LL | libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ eventfd: blocking is unsupported + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = note: BACKTRACE: + = note: inside `main` at $DIR/libc_eventfd_write_block.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/intrinsics/ptr_metadata_uninit_slice_data.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs index ff23f1e729e..0c305eed6e1 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs @@ -7,10 +7,12 @@ use std::intrinsics::mir::*; #[custom_mir(dialect = "runtime")] pub unsafe fn deref_meta(p: *const *const [i32]) -> usize { - mir!({ - RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data - Return() - }) + mir! { + { + RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data + Return() + } + } } fn main() { diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr index 61e1541d1ee..6478dcc2507 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory --> $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC | -LL | RET = PtrMetadata(*p); - | ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | RET = PtrMetadata(*p); + | ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory | = 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_metadata_uninit_slice_len.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs index 65f74c0acdd..a2ffdc92c4e 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs @@ -7,10 +7,12 @@ use std::intrinsics::mir::*; #[custom_mir(dialect = "runtime")] pub unsafe fn deref_meta(p: *const *const [i32]) -> usize { - mir!({ - RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data - Return() - }) + mir! { + { + RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data + Return() + } + } } fn main() { diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr index de559263a32..4e2e7218432 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr @@ -16,8 +16,8 @@ LL | (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32; error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory --> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC | -LL | RET = PtrMetadata(*p); - | ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | RET = PtrMetadata(*p); + | ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory | = 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_metadata_uninit_thin.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs index ad2e9fc800e..e5a51289a8a 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs @@ -7,10 +7,12 @@ use std::intrinsics::mir::*; #[custom_mir(dialect = "runtime")] pub unsafe fn deref_meta(p: *const *const i32) -> () { - mir!({ - RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data - Return() - }) + mir! { + { + RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data + Return() + } + } } fn main() { diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr index 3ab2643afa7..0e218de0eeb 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory --> $DIR/ptr_metadata_uninit_thin.rs:LL:CC | -LL | RET = PtrMetadata(*p); - | ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | RET = PtrMetadata(*p); + | ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory | = 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/issue-miri-2432.rs b/src/tools/miri/tests/fail/issue-miri-2432.rs deleted file mode 100644 index f822479c436..00000000000 --- a/src/tools/miri/tests/fail/issue-miri-2432.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![allow(where_clauses_object_safety)] - -trait Trait {} - -trait X { - fn foo(&self) - where - Self: Trait; -} - -impl X for () { - fn foo(&self) {} -} - -impl Trait for dyn X {} - -pub fn main() { - <dyn X as X>::foo(&()); //~ERROR: trying to call something that is not a method -} diff --git a/src/tools/miri/tests/fail/issue-miri-2432.stderr b/src/tools/miri/tests/fail/issue-miri-2432.stderr deleted file mode 100644 index 3befe31dc5a..00000000000 --- a/src/tools/miri/tests/fail/issue-miri-2432.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: `dyn` call trying to call something that is not a method - --> $DIR/issue-miri-2432.rs:LL:CC - | -LL | <dyn X as X>::foo(&()); - | ^^^^^^^^^^^^^^^^^^^^^^ `dyn` call trying to call something that is not a method - | - = 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/issue-miri-2432.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs new file mode 100644 index 00000000000..a3567eeb7cb --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs @@ -0,0 +1,108 @@ +//@only-target-linux +// test_race depends on a deterministic schedule. +//@compile-flags: -Zmiri-preemption-rate=0 + +use std::thread; + +fn main() { + test_read_write(); + test_race(); +} + +fn read_bytes<const N: usize>(fd: i32, buf: &mut [u8; N]) -> i32 { + let res: i32 = unsafe { libc::read(fd, buf.as_mut_ptr().cast(), N).try_into().unwrap() }; + return res; +} + +fn write_bytes<const N: usize>(fd: i32, data: [u8; N]) -> i32 { + let res: i32 = + unsafe { libc::write(fd, data.as_ptr() as *const libc::c_void, N).try_into().unwrap() }; + return res; +} + +fn test_read_write() { + let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC; + let fd = unsafe { libc::eventfd(0, flags) }; + let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes(); + // Write 1 to the counter. + let res = write_bytes(fd, sized_8_data); + assert_eq!(res, 8); + + // Read 1 from the counter. + let mut buf: [u8; 8] = [0; 8]; + let res = read_bytes(fd, &mut buf); + // Read returns number of bytes has been read, which is always 8. + assert_eq!(res, 8); + // Check the value of counter read. + let counter = u64::from_ne_bytes(buf); + assert_eq!(counter, 1); + + // After read, the counter is currently 0, read counter 0 should fail with return + // value -1. + let mut buf: [u8; 8] = [0; 8]; + let res = read_bytes(fd, &mut buf); + let e = std::io::Error::last_os_error(); + assert_eq!(e.raw_os_error(), Some(libc::EAGAIN)); + assert_eq!(res, -1); + + // Write with supplied buffer bigger than 8 bytes should be allowed. + let sized_9_data: [u8; 9]; + if cfg!(target_endian = "big") { + // Adjust the data based on the endianness of host system. + sized_9_data = [0, 0, 0, 0, 0, 0, 0, 1, 0]; + } else { + sized_9_data = [1, 0, 0, 0, 0, 0, 0, 0, 0]; + } + let res = write_bytes(fd, sized_9_data); + assert_eq!(res, 8); + + // Read with supplied buffer smaller than 8 bytes should fail with return + // value -1. + let mut buf: [u8; 7] = [1; 7]; + let res = read_bytes(fd, &mut buf); + let e = std::io::Error::last_os_error(); + assert_eq!(e.raw_os_error(), Some(libc::EINVAL)); + assert_eq!(res, -1); + + // Write with supplied buffer smaller than 8 bytes should fail with return + // value -1. + let size_7_data: [u8; 7] = [1; 7]; + let res = write_bytes(fd, size_7_data); + let e = std::io::Error::last_os_error(); + assert_eq!(e.raw_os_error(), Some(libc::EINVAL)); + assert_eq!(res, -1); + + // Read with supplied buffer bigger than 8 bytes should be allowed. + let mut buf: [u8; 9] = [1; 9]; + let res = read_bytes(fd, &mut buf); + assert_eq!(res, 8); + + // Write u64::MAX should fail. + let u64_max_bytes: [u8; 8] = [255; 8]; + let res = write_bytes(fd, u64_max_bytes); + let e = std::io::Error::last_os_error(); + assert_eq!(e.raw_os_error(), Some(libc::EINVAL)); + assert_eq!(res, -1); +} + +fn test_race() { + static mut VAL: u8 = 0; + let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC; + let fd = unsafe { libc::eventfd(0, flags) }; + let thread1 = thread::spawn(move || { + let mut buf: [u8; 8] = [0; 8]; + let res = read_bytes(fd, &mut buf); + // read returns number of bytes has been read, which is always 8. + assert_eq!(res, 8); + let counter = u64::from_ne_bytes(buf); + assert_eq!(counter, 1); + unsafe { assert_eq!(VAL, 1) }; + }); + unsafe { VAL = 1 }; + let data: [u8; 8] = 1_u64.to_ne_bytes(); + let res = write_bytes(fd, data); + // write returns number of bytes written, which is always 8. + assert_eq!(res, 8); + thread::yield_now(); + thread1.join().unwrap(); +} diff --git a/src/tools/miri/tests/pass/drop_in_place.rs b/src/tools/miri/tests/pass/drop_in_place.rs index 0615a43c800..cac8d76dd9d 100644 --- a/src/tools/miri/tests/pass/drop_in_place.rs +++ b/src/tools/miri/tests/pass/drop_in_place.rs @@ -6,7 +6,5 @@ use std::ptr; fn main() { let mut not_a_bool = 13u8; - unsafe { - ptr::drop_in_place(&mut not_a_bool as *mut u8 as *mut bool) - }; + unsafe { ptr::drop_in_place(&mut not_a_bool as *mut u8 as *mut bool) }; } 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 136660a305a..0cfcd532ff4 100644 --- a/src/tools/miri/tests/pass/function_calls/abi_compat.rs +++ b/src/tools/miri/tests/pass/function_calls/abi_compat.rs @@ -83,12 +83,24 @@ fn main() { test_abi_compat(main as fn(), id::<i32> as fn(i32) -> i32); // - 1-ZST test_abi_compat((), [0u8; 0]); - // - Guaranteed null-pointer-optimizations (RFC 3391). + // - Guaranteed Option<X> 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::NonZero::new(1u32).unwrap())); test_abi_compat(&0u32 as *const u32, Some(Wrapper(&0u32))); - test_abi_compat(0u32, Some(Wrapper(num::NonZero::new(1u32).unwrap()))); + test_abi_compat(0u32, Some(Wrapper(num::NonZeroU32::new(1u32).unwrap()))); + // - Guaranteed Result<X, ZST1> does the same as Option<X> (RFC 3391) + test_abi_compat(&0u32 as *const u32, Result::<_, ()>::Ok(&0u32)); + test_abi_compat(main as fn(), Result::<_, ()>::Ok(main as fn())); + test_abi_compat(0u32, Result::<_, ()>::Ok(num::NonZeroU32::new(1).unwrap())); + test_abi_compat(&0u32 as *const u32, Result::<_, ()>::Ok(Wrapper(&0u32))); + test_abi_compat(0u32, Result::<_, ()>::Ok(Wrapper(num::NonZeroU32::new(1).unwrap()))); + // - Guaranteed Result<ZST1, X> also does the same as Option<X> (RFC 3391) + test_abi_compat(&0u32 as *const u32, Result::<(), _>::Err(&0u32)); + test_abi_compat(main as fn(), Result::<(), _>::Err(main as fn())); + test_abi_compat(0u32, Result::<(), _>::Err(num::NonZeroU32::new(1).unwrap())); + test_abi_compat(&0u32 as *const u32, Result::<(), _>::Err(Wrapper(&0u32))); + test_abi_compat(0u32, Result::<(), _>::Err(Wrapper(num::NonZeroU32::new(1).unwrap()))); // These must work for *any* type, since we guarantee that `repr(transparent)` is ABI-compatible // with the wrapped field. diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs index 248a57d6850..03d9fc0a76f 100644 --- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs +++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-strict-provenance -#![feature(portable_simd, adt_const_params, core_intrinsics)] +#![feature(portable_simd, adt_const_params, core_intrinsics, repr_simd)] #![allow(incomplete_features, internal_features)] use std::intrinsics::simd as intrinsics; use std::ptr; @@ -318,6 +318,83 @@ fn simd_mask() { assert_eq!(selected1, i32x4::from_array([0, 0, 0, 1])); assert_eq!(selected2, selected1); } + + // Non-power-of-2 multi-byte mask. + #[repr(simd, packed)] + #[allow(non_camel_case_types)] + #[derive(Copy, Clone, Debug, PartialEq)] + struct i32x10([i32; 10]); + impl i32x10 { + fn splat(x: i32) -> Self { + Self([x; 10]) + } + } + unsafe { + let mask = i32x10([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0]); + let mask_bits = if cfg!(target_endian = "little") { 0b0101001011 } else { 0b1101001010 }; + let mask_bytes = + if cfg!(target_endian = "little") { [0b01001011, 0b01] } else { [0b11, 0b01001010] }; + + let bitmask1: u16 = simd_bitmask(mask); + let bitmask2: [u8; 2] = simd_bitmask(mask); + assert_eq!(bitmask1, mask_bits); + assert_eq!(bitmask2, mask_bytes); + + let selected1 = simd_select_bitmask::<u16, _>( + mask_bits, + i32x10::splat(!0), // yes + i32x10::splat(0), // no + ); + let selected2 = simd_select_bitmask::<[u8; 2], _>( + mask_bytes, + i32x10::splat(!0), // yes + i32x10::splat(0), // no + ); + assert_eq!(selected1, mask); + assert_eq!(selected2, mask); + } + + // Test for a mask where the next multiple of 8 is not a power of two. + #[repr(simd, packed)] + #[allow(non_camel_case_types)] + #[derive(Copy, Clone, Debug, PartialEq)] + struct i32x20([i32; 20]); + impl i32x20 { + fn splat(x: i32) -> Self { + Self([x; 20]) + } + } + unsafe { + let mask = i32x20([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0, 0, 0, 0, !0, !0, !0, !0, !0, !0, !0]); + let mask_bits = if cfg!(target_endian = "little") { + 0b11111110000101001011 + } else { + 0b11010010100001111111 + }; + let mask_bytes = if cfg!(target_endian = "little") { + [0b01001011, 0b11100001, 0b1111] + } else { + [0b1101, 0b00101000, 0b01111111] + }; + + let bitmask1: u32 = simd_bitmask(mask); + let bitmask2: [u8; 3] = simd_bitmask(mask); + assert_eq!(bitmask1, mask_bits); + assert_eq!(bitmask2, mask_bytes); + + let selected1 = simd_select_bitmask::<u32, _>( + mask_bits, + i32x20::splat(!0), // yes + i32x20::splat(0), // no + ); + let selected2 = simd_select_bitmask::<[u8; 3], _>( + mask_bytes, + i32x20::splat(!0), // yes + i32x20::splat(0), // no + ); + assert_eq!(selected1, mask); + assert_eq!(selected2, mask); + } } fn simd_cast() { @@ -581,11 +658,32 @@ fn simd_masked_loadstore() { assert_eq!(buf, [2, 3, 4]); } +fn simd_ops_non_pow2() { + // Just a little smoke test for operations on non-power-of-two vectors. + #[repr(simd, packed)] + #[derive(Copy, Clone)] + pub struct SimdPacked<T, const N: usize>([T; N]); + #[repr(simd)] + #[derive(Copy, Clone)] + pub struct SimdPadded<T, const N: usize>([T; N]); + + let x = SimdPacked([1u32; 3]); + let y = SimdPacked([2u32; 3]); + let z = unsafe { intrinsics::simd_add(x, y) }; + assert_eq!({ z.0 }, [3u32; 3]); + + let x = SimdPadded([1u32; 3]); + let y = SimdPadded([2u32; 3]); + let z = unsafe { intrinsics::simd_add(x, y) }; + assert_eq!(z.0, [3u32; 3]); +} + fn main() { simd_mask(); simd_ops_f32(); simd_ops_f64(); simd_ops_i32(); + simd_ops_non_pow2(); simd_cast(); simd_swizzle(); simd_gather_scatter(); diff --git a/src/tools/miri/tests/pass/shims/env/var.rs b/src/tools/miri/tests/pass/shims/env/var.rs index babaf00578a..a576c1fc8bb 100644 --- a/src/tools/miri/tests/pass/shims/env/var.rs +++ b/src/tools/miri/tests/pass/shims/env/var.rs @@ -1,3 +1,4 @@ +//@compile-flags: -Zmiri-preemption-rate=0 use std::env; use std::thread; @@ -26,6 +27,8 @@ fn main() { println!("{:#?}", env::vars().collect::<Vec<_>>()); // Do things concurrently, to make sure there's no data race. + // We disable preemption to make sure the lock is not contended; + // that means we don't hit e.g. the futex codepath on Android (which we don't support). let t = thread::spawn(|| { env::set_var("MIRI_TEST", "42"); }); diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pclmulqdq.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pclmulqdq.rs new file mode 100644 index 00000000000..2f242dd5379 --- /dev/null +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pclmulqdq.rs @@ -0,0 +1,48 @@ +// Ignore everything except x86 and x86_64 +// Any new targets that are added to CI should be ignored here. +// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) +//@ignore-target-aarch64 +//@ignore-target-arm +//@ignore-target-avr +//@ignore-target-s390x +//@ignore-target-thumbv7em +//@ignore-target-wasm32 +//@compile-flags: -C target-feature=+pclmulqdq + +#[cfg(target_arch = "x86")] +use std::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; + +fn main() { + assert!(is_x86_feature_detected!("pclmulqdq")); + + let a = (0x7fffffffffffffff, 0x4317e40ab4ddcf05); + let b = (0xdd358416f52ecd34, 0x633d11cc638ca16b); + + unsafe { + assert_eq!(clmulepi64_si128::<0x00>(a, b), (13036940098130298092, 2704901987789626761)); + assert_eq!(clmulepi64_si128::<0x01>(a, b), (6707488474444649956, 3901733953304450635)); + assert_eq!(clmulepi64_si128::<0x10>(a, b), (11607166829323378905, 1191897396234301548)); + assert_eq!(clmulepi64_si128::<0x11>(a, b), (7731954893213347271, 1760130762532070957)); + } +} + +#[target_feature(enable = "pclmulqdq")] +unsafe fn clmulepi64_si128<const IMM8: i32>( + (a1, a2): (u64, u64), + (b1, b2): (u64, u64), +) -> (u64, u64) { + // SAFETY: There are no safety requirements for calling `_mm_clmulepi64_si128`. + // It's just unsafe for API consistency with other intrinsics. + unsafe { + let a = core::mem::transmute::<_, __m128i>([a1, a2]); + let b = core::mem::transmute::<_, __m128i>([b1, b2]); + + let out = _mm_clmulepi64_si128::<IMM8>(a, b); + + let [c1, c2] = core::mem::transmute::<_, [u64; 2]>(out); + + (c1, c2) + } +} diff --git a/src/tools/opt-dist/src/environment.rs b/src/tools/opt-dist/src/environment.rs index ff782a1687e..bc01b7fb8a3 100644 --- a/src/tools/opt-dist/src/environment.rs +++ b/src/tools/opt-dist/src/environment.rs @@ -17,6 +17,9 @@ pub struct Environment { host_llvm_dir: Utf8PathBuf, /// List of test paths that should be skipped when testing the optimized artifacts. skipped_tests: Vec<String>, + /// Arguments passed to `rustc-perf --cargo-config <value>` when running benchmarks. + #[builder(default)] + benchmark_cargo_config: Vec<String>, /// Directory containing a pre-built rustc-perf checkout. #[builder(default)] prebuilt_rustc_perf: Option<Utf8PathBuf>, @@ -94,6 +97,10 @@ impl Environment { pub fn skipped_tests(&self) -> &[String] { &self.skipped_tests } + + pub fn benchmark_cargo_config(&self) -> &[String] { + &self.benchmark_cargo_config + } } /// What is the extension of binary executables on this platform? diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index a709076f245..e4271a6e2dd 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -90,6 +90,10 @@ enum EnvironmentCmd { #[clap(flatten)] shared: SharedArgs, + + /// Arguments passed to `rustc-perf --cargo-config <value>` when running benchmarks. + #[arg(long)] + benchmark_cargo_config: Vec<String>, }, /// Perform an optimized build on Linux CI, from inside Docker. LinuxCi { @@ -119,6 +123,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)> llvm_shared, use_bolt, skipped_tests, + benchmark_cargo_config, shared, } => { let env = EnvironmentBuilder::default() @@ -132,6 +137,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)> .shared_llvm(llvm_shared) .use_bolt(use_bolt) .skipped_tests(skipped_tests) + .benchmark_cargo_config(benchmark_cargo_config) .build()?; (env, shared.build_args) diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs index 46040e32a03..89f4d8957c8 100644 --- a/src/tools/opt-dist/src/training.rs +++ b/src/tools/opt-dist/src/training.rs @@ -3,30 +3,10 @@ use crate::exec::{cmd, CmdBuilder}; use crate::utils::io::{count_files, delete_directory}; use crate::utils::with_log_group; use anyhow::Context; +use build_helper::{LLVM_PGO_CRATES, RUSTC_PGO_CRATES}; use camino::{Utf8Path, Utf8PathBuf}; use humansize::BINARY; -const LLVM_PGO_CRATES: &[&str] = &[ - "syn-1.0.89", - "cargo-0.60.0", - "serde-1.0.136", - "ripgrep-13.0.0", - "regex-1.5.5", - "clap-3.1.6", - "hyper-0.14.18", -]; - -const RUSTC_PGO_CRATES: &[&str] = &[ - "externs", - "ctfe-stress-5", - "cargo-0.60.0", - "token-stream-stress", - "match-stress", - "tuple-stress", - "diesel-1.4.8", - "bitmaps-3.1.0", -]; - fn init_compiler_benchmarks( env: &Environment, profiles: &[&str], @@ -36,7 +16,7 @@ fn init_compiler_benchmarks( // Run rustc-perf benchmarks // Benchmark using profile_local with eprintln, which essentially just means // don't actually benchmark -- just make sure we run rustc a bunch of times. - cmd(&[ + let mut cmd = cmd(&[ env.cargo_stage_0().as_str(), "run", "-p", @@ -61,7 +41,17 @@ fn init_compiler_benchmarks( .env("RUST_LOG", "collector=debug") .env("RUSTC", env.rustc_stage_0().as_str()) .env("RUSTC_BOOTSTRAP", "1") - .workdir(&env.rustc_perf_dir()) + .workdir(&env.rustc_perf_dir()); + + // This propagates cargo configs to `rustc-perf --cargo-config`, + // which is particularly useful when the environment is air-gapped, + // and you want to use the default set of training crates vendored + // in the rustc-src tarball. + for config in env.benchmark_cargo_config() { + cmd = cmd.arg("--cargo-config").arg(config); + } + + cmd } /// Describes which `llvm-profdata` binary should be used for merging PGO profiles. diff --git a/src/tools/run-make-support/src/cc.rs b/src/tools/run-make-support/src/cc.rs index 0012e7b66af..5c0158d7547 100644 --- a/src/tools/run-make-support/src/cc.rs +++ b/src/tools/run-make-support/src/cc.rs @@ -1,8 +1,7 @@ -use std::env; use std::path::Path; -use std::process::Command; -use crate::{bin_name, cygpath_windows, handle_failed_output, is_msvc, is_windows, tmp_dir, uname}; +use crate::command::Command; +use crate::{bin_name, cygpath_windows, env_var, is_msvc, is_windows, uname}; /// Construct a new platform-specific C compiler invocation. /// @@ -27,11 +26,11 @@ impl Cc { /// WARNING: This means that what flags are accepted by the underlying C compile is /// platform- AND compiler-specific. Consult the relevant docs for `gcc`, `clang` and `mvsc`. pub fn new() -> Self { - let compiler = env::var("CC").unwrap(); + let compiler = env_var("CC"); let mut cmd = Command::new(compiler); - let default_cflags = env::var("CC_DEFAULT_FLAGS").unwrap(); + let default_cflags = env_var("CC_DEFAULT_FLAGS"); for flag in default_cflags.split(char::is_whitespace) { cmd.arg(flag); } @@ -53,8 +52,7 @@ impl Cc { self } - /// Specify `-o` or `-Fe`/`-Fo` depending on platform/compiler. This assumes that the executable - /// is under `$TMPDIR`. + /// Specify `-o` or `-Fe`/`-Fo` depending on platform/compiler. pub fn out_exe(&mut self, name: &str) -> &mut Self { // Ref: tools.mk (irrelevant lines omitted): // @@ -68,13 +66,13 @@ impl Cc { // ``` if is_msvc() { - let fe_path = cygpath_windows(tmp_dir().join(bin_name(name))); - let fo_path = cygpath_windows(tmp_dir().join(format!("{name}.obj"))); + let fe_path = cygpath_windows(bin_name(name)); + let fo_path = cygpath_windows(format!("{name}.obj")); self.cmd.arg(format!("-Fe:{fe_path}")); self.cmd.arg(format!("-Fo:{fo_path}")); } else { self.cmd.arg("-o"); - self.cmd.arg(tmp_dir().join(name)); + self.cmd.arg(name); } self diff --git a/src/tools/run-make-support/src/clang.rs b/src/tools/run-make-support/src/clang.rs index 6ccce67b250..d2ebed7ab06 100644 --- a/src/tools/run-make-support/src/clang.rs +++ b/src/tools/run-make-support/src/clang.rs @@ -1,8 +1,7 @@ -use std::env; use std::path::Path; -use std::process::Command; -use crate::{bin_name, handle_failed_output, tmp_dir}; +use crate::command::Command; +use crate::{bin_name, env_var}; /// Construct a new `clang` invocation. `clang` is not always available for all targets. pub fn clang() -> Clang { @@ -20,8 +19,7 @@ crate::impl_common_helpers!(Clang); impl Clang { /// Construct a new `clang` invocation. `clang` is not always available for all targets. pub fn new() -> Self { - let clang = - env::var("CLANG").expect("`CLANG` not specified, but this is required to find `clang`"); + let clang = env_var("CLANG"); let cmd = Command::new(clang); Self { cmd } } @@ -32,11 +30,11 @@ impl Clang { self } - /// Specify the name of the executable. The executable will be placed under `$TMPDIR`, and the - /// extension will be determined by [`bin_name`]. + /// Specify the name of the executable. The executable will be placed under the current directory + /// and the extension will be determined by [`bin_name`]. pub fn out_exe(&mut self, name: &str) -> &mut Self { self.cmd.arg("-o"); - self.cmd.arg(tmp_dir().join(bin_name(name))); + self.cmd.arg(bin_name(name)); self } @@ -70,9 +68,4 @@ impl Clang { self.cmd.arg(format!("-fuse-ld={ld}")); self } - - /// Get the [`Output`][::std::process::Output] of the finished process. - 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/command.rs b/src/tools/run-make-support/src/command.rs new file mode 100644 index 00000000000..cc395e491ee --- /dev/null +++ b/src/tools/run-make-support/src/command.rs @@ -0,0 +1,151 @@ +use crate::{assert_not_contains, handle_failed_output}; +use std::ffi::OsStr; +use std::io::Write; +use std::ops::{Deref, DerefMut}; +use std::process::{Command as StdCommand, ExitStatus, Output, Stdio}; + +/// This is a custom command wrapper that simplifies working with commands +/// and makes it easier to ensure that we check the exit status of executed +/// processes. +#[derive(Debug)] +pub struct Command { + cmd: StdCommand, + stdin: Option<Box<[u8]>>, +} + +impl Command { + pub fn new<S: AsRef<OsStr>>(program: S) -> Self { + Self { cmd: StdCommand::new(program), stdin: None } + } + + pub fn set_stdin(&mut self, stdin: Box<[u8]>) { + self.stdin = Some(stdin); + } + + /// Run the constructed command and assert that it is successfully run. + #[track_caller] + pub fn run(&mut self) -> CompletedProcess { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let output = self.command_output(); + if !output.status().success() { + handle_failed_output(&self, output, caller_line_number); + } + output + } + + /// Run the constructed command and assert that it does not successfully run. + #[track_caller] + pub fn run_fail(&mut self) -> CompletedProcess { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let output = self.command_output(); + if output.status().success() { + handle_failed_output(&self, output, caller_line_number); + } + output + } + + #[track_caller] + pub(crate) fn command_output(&mut self) -> CompletedProcess { + // let's make sure we piped all the input and outputs + self.cmd.stdin(Stdio::piped()); + self.cmd.stdout(Stdio::piped()); + self.cmd.stderr(Stdio::piped()); + + let output = if let Some(input) = &self.stdin { + let mut child = self.cmd.spawn().unwrap(); + + { + let mut stdin = child.stdin.take().unwrap(); + stdin.write_all(input.as_ref()).unwrap(); + } + + child.wait_with_output().expect("failed to get output of finished process") + } else { + self.cmd.output().expect("failed to get output of finished process") + }; + output.into() + } +} + +impl Deref for Command { + type Target = StdCommand; + + fn deref(&self) -> &Self::Target { + &self.cmd + } +} + +impl DerefMut for Command { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.cmd + } +} + +/// Represents the result of an executed process. +/// The various `assert_` helper methods should preferably be used for +/// checking the contents of stdout/stderr. +pub struct CompletedProcess { + output: Output, +} + +impl CompletedProcess { + pub fn stdout_utf8(&self) -> String { + String::from_utf8(self.output.stdout.clone()).expect("stdout is not valid UTF-8") + } + + pub fn stderr_utf8(&self) -> String { + String::from_utf8(self.output.stderr.clone()).expect("stderr is not valid UTF-8") + } + + pub fn status(&self) -> ExitStatus { + self.output.status + } + + /// Checks that trimmed `stdout` matches trimmed `content`. + #[track_caller] + pub fn assert_stdout_equals<S: AsRef<str>>(&self, content: S) -> &Self { + assert_eq!(self.stdout_utf8().trim(), content.as_ref().trim()); + self + } + + #[track_caller] + pub fn assert_stdout_not_contains<S: AsRef<str>>(&self, needle: S) -> &Self { + assert_not_contains(&self.stdout_utf8(), needle.as_ref()); + self + } + + /// Checks that trimmed `stderr` matches trimmed `content`. + #[track_caller] + pub fn assert_stderr_equals<S: AsRef<str>>(&self, content: S) -> &Self { + assert_eq!(self.stderr_utf8().trim(), content.as_ref().trim()); + self + } + + #[track_caller] + pub fn assert_stderr_contains<S: AsRef<str>>(&self, needle: S) -> &Self { + assert!(self.stderr_utf8().contains(needle.as_ref())); + self + } + + #[track_caller] + pub fn assert_stderr_not_contains<S: AsRef<str>>(&self, needle: S) -> &Self { + assert_not_contains(&self.stdout_utf8(), needle.as_ref()); + self + } + + #[track_caller] + pub fn assert_exit_code(&self, code: i32) -> &Self { + assert!(self.output.status.code() == Some(code)); + self + } +} + +impl From<Output> for CompletedProcess { + fn from(output: Output) -> Self { + Self { output } + } +} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 323fc40e648..960f4bcd254 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -5,6 +5,7 @@ pub mod cc; pub mod clang; +mod command; pub mod diff; pub mod llvm_readobj; pub mod run; @@ -12,10 +13,10 @@ pub mod rustc; pub mod rustdoc; use std::env; +use std::ffi::OsString; use std::fs; use std::io; use std::path::{Path, PathBuf}; -use std::process::{Command, Output}; pub use gimli; pub use object; @@ -26,18 +27,27 @@ pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc}; pub use clang::{clang, Clang}; pub use diff::{diff, Diff}; pub use llvm_readobj::{llvm_readobj, LlvmReadobj}; -pub use run::{run, run_fail}; +pub use run::{cmd, run, run_fail}; pub use rustc::{aux_build, rustc, Rustc}; pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; -/// Path of `TMPDIR` (a temporary build directory, not under `/tmp`). -pub fn tmp_dir() -> PathBuf { - env::var_os("TMPDIR").unwrap().into() +pub fn env_var(name: &str) -> String { + match env::var(name) { + Ok(v) => v, + Err(err) => panic!("failed to retrieve environment variable {name:?}: {err:?}"), + } +} + +pub fn env_var_os(name: &str) -> OsString { + match env::var_os(name) { + Some(v) => v, + None => panic!("failed to retrieve environment variable {name:?}"), + } } /// `TARGET` pub fn target() -> String { - env::var("TARGET").unwrap() + env_var("TARGET") } /// Check if target is windows-like. @@ -55,25 +65,25 @@ pub fn is_darwin() -> bool { target().contains("darwin") } -/// Construct a path to a static library under `$TMPDIR` given the library name. This will return a -/// path with `$TMPDIR` joined with platform-and-compiler-specific library name. -pub fn static_lib(name: &str) -> PathBuf { - tmp_dir().join(static_lib_name(name)) -} - pub fn python_command() -> Command { - let python_path = std::env::var("PYTHON").expect("PYTHON environment variable does not exist"); + let python_path = env_var("PYTHON"); Command::new(python_path) } pub fn htmldocck() -> Command { let mut python = python_command(); - python.arg(source_path().join("src/etc/htmldocck.py")); + python.arg(source_root().join("src/etc/htmldocck.py")); python } -pub fn source_path() -> PathBuf { - std::env::var("S").expect("S variable does not exist").into() +/// Returns the path for a local test file. +pub fn path<P: AsRef<Path>>(p: P) -> PathBuf { + cwd().join(p.as_ref()) +} + +/// Path to the root rust-lang/rust source checkout. +pub fn source_root() -> PathBuf { + env_var("SOURCE_ROOT").into() } /// Construct the static library name based on the platform. @@ -100,12 +110,6 @@ pub fn static_lib_name(name: &str) -> String { if is_msvc() { format!("{name}.lib") } else { format!("lib{name}.a") } } -/// Construct a path to a dynamic library under `$TMPDIR` given the library name. This will return a -/// path with `$TMPDIR` joined with platform-and-compiler-specific library name. -pub fn dynamic_lib(name: &str) -> PathBuf { - tmp_dir().join(dynamic_lib_name(name)) -} - /// Construct the dynamic library name based on the platform. pub fn dynamic_lib_name(name: &str) -> String { // See tools.mk (irrelevant lines omitted): @@ -143,14 +147,7 @@ pub fn dynamic_lib_extension() -> &'static str { } } -/// Construct a path to a rust library (rlib) under `$TMPDIR` given the library name. This will return a -/// path with `$TMPDIR` joined with the library name. -pub fn rust_lib(name: &str) -> PathBuf { - tmp_dir().join(rust_lib_name(name)) -} - -/// Generate the name a rust library (rlib) would have. If you want the complete path, use -/// [`rust_lib`] instead. +/// Construct a rust library (rlib) name. pub fn rust_lib_name(name: &str) -> String { format!("lib{name}.rlib") } @@ -160,6 +157,11 @@ pub fn bin_name(name: &str) -> String { if is_windows() { format!("{name}.exe") } else { name.to_string() } } +/// Return the current working directory. +pub fn cwd() -> PathBuf { + env::current_dir().unwrap() +} + /// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is /// available on the platform! #[track_caller] @@ -170,13 +172,12 @@ pub fn cygpath_windows<P: AsRef<Path>>(path: P) -> String { let mut cygpath = Command::new("cygpath"); cygpath.arg("-w"); cygpath.arg(path.as_ref()); - let output = cygpath.output().unwrap(); - if !output.status.success() { + let output = cygpath.command_output(); + if !output.status().success() { handle_failed_output(&cygpath, output, caller_line_number); } - let s = String::from_utf8(output.stdout).unwrap(); // cygpath -w can attach a newline - s.trim().to_string() + output.stdout_utf8().trim().to_string() } /// Run `uname`. This assumes that `uname` is available on the platform! @@ -186,34 +187,34 @@ pub fn uname() -> String { let caller_line_number = caller_location.line(); let mut uname = Command::new("uname"); - let output = uname.output().unwrap(); - if !output.status.success() { + let output = uname.command_output(); + if !output.status().success() { handle_failed_output(&uname, output, caller_line_number); } - String::from_utf8(output.stdout).unwrap() + output.stdout_utf8() } -fn handle_failed_output(cmd: &Command, output: Output, caller_line_number: u32) -> ! { - if output.status.success() { +fn handle_failed_output(cmd: &Command, output: CompletedProcess, caller_line_number: u32) -> ! { + if output.status().success() { eprintln!("command unexpectedly succeeded at line {caller_line_number}"); } else { eprintln!("command failed at line {caller_line_number}"); } eprintln!("{cmd:?}"); - eprintln!("output status: `{}`", output.status); - eprintln!("=== STDOUT ===\n{}\n\n", String::from_utf8(output.stdout).unwrap()); - eprintln!("=== STDERR ===\n{}\n\n", String::from_utf8(output.stderr).unwrap()); + eprintln!("output status: `{}`", output.status()); + eprintln!("=== STDOUT ===\n{}\n\n", output.stdout_utf8()); + eprintln!("=== STDERR ===\n{}\n\n", output.stderr_utf8()); std::process::exit(1) } /// Set the runtime library path as needed for running the host rustc/rustdoc/etc. pub fn set_host_rpath(cmd: &mut Command) { - let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap(); + let ld_lib_path_envvar = env_var("LD_LIB_PATH_ENVVAR"); cmd.env(&ld_lib_path_envvar, { let mut paths = vec![]; - paths.push(PathBuf::from(env::var("TMPDIR").unwrap())); - paths.push(PathBuf::from(env::var("HOST_RPATH_DIR").unwrap())); - for p in env::split_paths(&env::var(&ld_lib_path_envvar).unwrap()) { + paths.push(cwd()); + paths.push(PathBuf::from(env_var("HOST_RPATH_DIR"))); + for p in env::split_paths(&env_var(&ld_lib_path_envvar)) { paths.push(p.to_path_buf()); } env::join_paths(paths.iter()).unwrap() @@ -289,6 +290,7 @@ pub fn read_dir<F: Fn(&Path)>(dir: impl AsRef<Path>, callback: F) { } /// Check that `haystack` does not contain `needle`. Panic otherwise. +#[track_caller] pub fn assert_not_contains(haystack: &str, needle: &str) { if haystack.contains(needle) { eprintln!("=== HAYSTACK ==="); @@ -299,39 +301,52 @@ pub fn assert_not_contains(haystack: &str, needle: &str) { } } +/// This function is designed for running commands in a temporary directory +/// that is cleared after the function ends. +/// +/// What this function does: +/// 1) Creates a temporary directory (`tmpdir`) +/// 2) Copies all files from the current directory to `tmpdir` +/// 3) Changes the current working directory to `tmpdir` +/// 4) Calls `callback` +/// 5) Switches working directory back to the original one +/// 6) Removes `tmpdir` +pub fn run_in_tmpdir<F: FnOnce()>(callback: F) { + let original_dir = cwd(); + let tmpdir = original_dir.join("../temporary-directory"); + copy_dir_all(".", &tmpdir); + + env::set_current_dir(&tmpdir).unwrap(); + callback(); + env::set_current_dir(original_dir).unwrap(); + fs::remove_dir_all(tmpdir).unwrap(); +} + /// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct -/// containing a `cmd: Command` field and a `output` function. The provided helpers are: +/// containing a `cmd: Command` field. The provided helpers are: /// /// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended /// to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add /// new specific helper methods over relying on these generic argument providers. /// 2. Environment manipulation methods: `env`, `env_remove` and `env_clear`: these delegate to /// methods of the same name on [`Command`]. -/// 3. Output and execution: `output`, `run` and `run_fail` are provided. `output` waits for the -/// command to finish running and returns the process's [`Output`]. `run` and `run_fail` are -/// higher-level convenience methods which waits for the command to finish running and assert -/// that the command successfully ran or failed as expected. Prefer `run` and `run_fail` when -/// possible. +/// 3. Output and execution: `run` and `run_fail` are provided. These are +/// higher-level convenience methods which wait for the command to finish running and assert +/// that the command successfully ran or failed as expected. They return +/// [`CompletedProcess`], which can be used to assert the stdout/stderr/exit code of the executed +/// process. /// /// Example usage: /// /// ```ignore (illustrative) /// struct CommandWrapper { cmd: Command } // <- required `cmd` field /// -/// impl CommandWrapper { -/// /// Get the [`Output`][::std::process::Output] of the finished process. -/// pub fn command_output(&mut self) -> Output { /* ... */ } // <- required `command_output()` method -/// } -/// /// crate::impl_common_helpers!(CommandWrapper); /// /// impl CommandWrapper { /// // ... additional specific helper methods /// } /// ``` -/// -/// [`Command`]: ::std::process::Command -/// [`Output`]: ::std::process::Output macro_rules! impl_common_helpers { ($wrapper: ident) => { impl $wrapper { @@ -394,28 +409,14 @@ macro_rules! impl_common_helpers { /// Run the constructed command and assert that it is successfully run. #[track_caller] - pub fn run(&mut self) -> ::std::process::Output { - let caller_location = ::std::panic::Location::caller(); - let caller_line_number = caller_location.line(); - - let output = self.command_output(); - if !output.status.success() { - handle_failed_output(&self.cmd, output, caller_line_number); - } - output + pub fn run(&mut self) -> crate::command::CompletedProcess { + self.cmd.run() } /// Run the constructed command and assert that it does not successfully run. #[track_caller] - pub fn run_fail(&mut self) -> ::std::process::Output { - let caller_location = ::std::panic::Location::caller(); - let caller_line_number = caller_location.line(); - - let output = self.command_output(); - if output.status.success() { - handle_failed_output(&self.cmd, output, caller_line_number); - } - output + pub fn run_fail(&mut self) -> crate::command::CompletedProcess { + self.cmd.run_fail() } /// Set the path where the command will be run. @@ -427,4 +428,5 @@ macro_rules! impl_common_helpers { }; } +use crate::command::{Command, CompletedProcess}; pub(crate) use impl_common_helpers; diff --git a/src/tools/run-make-support/src/llvm_readobj.rs b/src/tools/run-make-support/src/llvm_readobj.rs index f114aacfa3f..db2f9db6e41 100644 --- a/src/tools/run-make-support/src/llvm_readobj.rs +++ b/src/tools/run-make-support/src/llvm_readobj.rs @@ -1,8 +1,7 @@ -use std::env; use std::path::{Path, PathBuf}; -use std::process::Command; -use crate::handle_failed_output; +use crate::command::Command; +use crate::env_var; /// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available /// at `$LLVM_BIN_DIR/llvm-readobj`. @@ -22,8 +21,7 @@ impl LlvmReadobj { /// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available /// at `$LLVM_BIN_DIR/llvm-readobj`. pub fn new() -> Self { - let llvm_bin_dir = env::var("LLVM_BIN_DIR") - .expect("`LLVM_BIN_DIR` not specified, but this is required to find `llvm-readobj`"); + let llvm_bin_dir = env_var("LLVM_BIN_DIR"); let llvm_bin_dir = PathBuf::from(llvm_bin_dir); let llvm_readobj = llvm_bin_dir.join("llvm-readobj"); let cmd = Command::new(llvm_readobj); @@ -41,10 +39,4 @@ impl LlvmReadobj { self.cmd.arg("--file-header"); self } - - /// Get the [`Output`][::std::process::Output] of the finished process. - #[track_caller] - 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/run.rs b/src/tools/run-make-support/src/run.rs index 9aad91f1b46..4a6fd7c432e 100644 --- a/src/tools/run-make-support/src/run.rs +++ b/src/tools/run-make-support/src/run.rs @@ -1,24 +1,25 @@ use std::env; +use std::ffi::OsStr; use std::path::{Path, PathBuf}; -use std::process::{Command, Output}; -use crate::is_windows; +use crate::command::{Command, CompletedProcess}; +use crate::{cwd, env_var, is_windows, set_host_rpath}; -use super::{bin_name, handle_failed_output}; +use super::handle_failed_output; -fn run_common(name: &str) -> (Command, Output) { +fn run_common(name: &str) -> (Command, CompletedProcess) { let mut bin_path = PathBuf::new(); - bin_path.push(env::var("TMPDIR").unwrap()); - bin_path.push(&bin_name(name)); - let ld_lib_path_envvar = env::var("LD_LIB_PATH_ENVVAR").unwrap(); + bin_path.push(cwd()); + bin_path.push(name); + let ld_lib_path_envvar = env_var("LD_LIB_PATH_ENVVAR"); let mut cmd = Command::new(bin_path); cmd.env(&ld_lib_path_envvar, { let mut paths = vec![]; - paths.push(PathBuf::from(env::var("TMPDIR").unwrap())); - for p in env::split_paths(&env::var("TARGET_RPATH_ENV").unwrap()) { + paths.push(cwd()); + for p in env::split_paths(&env_var("TARGET_RPATH_ENV")) { paths.push(p.to_path_buf()); } - for p in env::split_paths(&env::var(&ld_lib_path_envvar).unwrap()) { + for p in env::split_paths(&env_var(&ld_lib_path_envvar)) { paths.push(p.to_path_buf()); } env::join_paths(paths.iter()).unwrap() @@ -29,22 +30,22 @@ fn run_common(name: &str) -> (Command, Output) { for p in env::split_paths(&std::env::var("PATH").unwrap_or(String::new())) { paths.push(p.to_path_buf()); } - paths.push(Path::new(&std::env::var("TARGET_RPATH_DIR").unwrap()).to_path_buf()); + paths.push(Path::new(&env_var("TARGET_RPATH_DIR")).to_path_buf()); cmd.env("PATH", env::join_paths(paths.iter()).unwrap()); } - let output = cmd.output().unwrap(); + let output = cmd.command_output(); (cmd, output) } /// Run a built binary and make sure it succeeds. #[track_caller] -pub fn run(name: &str) -> Output { +pub fn run(name: &str) -> CompletedProcess { let caller_location = std::panic::Location::caller(); let caller_line_number = caller_location.line(); let (cmd, output) = run_common(name); - if !output.status.success() { + if !output.status().success() { handle_failed_output(&cmd, output, caller_line_number); } output @@ -52,13 +53,21 @@ pub fn run(name: &str) -> Output { /// Run a built binary and make sure it fails. #[track_caller] -pub fn run_fail(name: &str) -> Output { +pub fn run_fail(name: &str) -> CompletedProcess { let caller_location = std::panic::Location::caller(); let caller_line_number = caller_location.line(); let (cmd, output) = run_common(name); - if output.status.success() { + if output.status().success() { handle_failed_output(&cmd, output, caller_line_number); } output } + +/// Create a new custom Command. +/// This should be preferred to creating `std::process::Command` directly. +pub fn cmd<S: AsRef<OsStr>>(program: S) -> Command { + let mut command = Command::new(program); + set_host_rpath(&mut command); + command +} diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index 8b0252b8f04..5ea231442bc 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -1,10 +1,8 @@ -use std::env; +use command::Command; use std::ffi::{OsStr, OsString}; -use std::io::Write; use std::path::Path; -use std::process::{Command, Output, Stdio}; -use crate::{handle_failed_output, set_host_rpath, tmp_dir}; +use crate::{command, cwd, env_var, set_host_rpath}; /// Construct a new `rustc` invocation. pub fn rustc() -> Rustc { @@ -20,16 +18,15 @@ pub fn aux_build() -> Rustc { #[derive(Debug)] pub struct Rustc { cmd: Command, - stdin: Option<Box<[u8]>>, } crate::impl_common_helpers!(Rustc); fn setup_common() -> Command { - let rustc = env::var("RUSTC").unwrap(); + let rustc = env_var("RUSTC"); let mut cmd = Command::new(rustc); set_host_rpath(&mut cmd); - cmd.arg("--out-dir").arg(tmp_dir()).arg("-L").arg(tmp_dir()); + cmd.arg("-L").arg(cwd()); cmd } @@ -39,14 +36,14 @@ impl Rustc { /// Construct a new `rustc` invocation. pub fn new() -> Self { let cmd = setup_common(); - Self { cmd, stdin: None } + Self { cmd } } /// Construct a new `rustc` invocation with `aux_build` preset (setting `--crate-type=lib`). pub fn new_aux_build() -> Self { let mut cmd = setup_common(); cmd.arg("--crate-type=lib"); - Self { cmd, stdin: None } + Self { cmd } } // Argument provider methods @@ -70,6 +67,12 @@ impl Rustc { self } + /// Add a suffix in each output filename. + pub fn extra_filename(&mut self, suffix: &str) -> &mut Self { + self.cmd.arg(format!("-Cextra-filename={suffix}")); + self + } + /// Specify type(s) of output files to generate. pub fn emit(&mut self, kinds: &str) -> &mut Self { self.cmd.arg(format!("--emit={kinds}")); @@ -104,6 +107,13 @@ impl Rustc { self } + /// Specify path to the output directory. Equivalent to `--out-dir`` in rustc. + pub fn out_dir<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { + self.cmd.arg("--out-dir"); + 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}")); @@ -192,7 +202,7 @@ impl Rustc { /// Specify a stdin input pub fn stdin<I: AsRef<[u8]>>(&mut self, input: I) -> &mut Self { - self.stdin = Some(input.as_ref().to_vec().into_boxed_slice()); + self.cmd.set_stdin(input.as_ref().to_vec().into_boxed_slice()); self } @@ -208,38 +218,4 @@ impl Rustc { self.cmd.arg(format!("-Clinker={linker}")); self } - - /// Get the [`Output`] of the finished process. - #[track_caller] - pub fn command_output(&mut self) -> Output { - // let's make sure we piped all the input and outputs - self.cmd.stdin(Stdio::piped()); - self.cmd.stdout(Stdio::piped()); - self.cmd.stderr(Stdio::piped()); - - if let Some(input) = &self.stdin { - let mut child = self.cmd.spawn().unwrap(); - - { - let mut stdin = child.stdin.take().unwrap(); - stdin.write_all(input.as_ref()).unwrap(); - } - - child.wait_with_output().expect("failed to get output of finished process") - } else { - self.cmd.output().expect("failed to get output of finished process") - } - } - - #[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.command_output(); - if output.status.code().unwrap() != code { - handle_failed_output(&self.cmd, output, caller_line_number); - } - output - } } diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs index 61d7448a6bf..39a698a47b4 100644 --- a/src/tools/run-make-support/src/rustdoc.rs +++ b/src/tools/run-make-support/src/rustdoc.rs @@ -1,10 +1,8 @@ -use std::env; use std::ffi::OsStr; -use std::io::Write; use std::path::Path; -use std::process::{Command, Output, Stdio}; -use crate::{handle_failed_output, set_host_rpath}; +use crate::command::Command; +use crate::{env_var, env_var_os, set_host_rpath}; /// Construct a plain `rustdoc` invocation with no flags set. pub fn bare_rustdoc() -> Rustdoc { @@ -19,13 +17,12 @@ pub fn rustdoc() -> Rustdoc { #[derive(Debug)] pub struct Rustdoc { cmd: Command, - stdin: Option<Box<[u8]>>, } crate::impl_common_helpers!(Rustdoc); fn setup_common() -> Command { - let rustdoc = env::var("RUSTDOC").unwrap(); + let rustdoc = env_var("RUSTDOC"); let mut cmd = Command::new(rustdoc); set_host_rpath(&mut cmd); cmd @@ -35,15 +32,15 @@ impl Rustdoc { /// Construct a bare `rustdoc` invocation. pub fn bare() -> Self { let cmd = setup_common(); - Self { cmd, stdin: None } + Self { cmd } } /// Construct a `rustdoc` invocation with `-L $(TARGET_RPATH_DIR)` set. pub fn new() -> Self { let mut cmd = setup_common(); - let target_rpath_dir = env::var_os("TARGET_RPATH_DIR").unwrap(); + let target_rpath_dir = env_var_os("TARGET_RPATH_DIR"); cmd.arg(format!("-L{}", target_rpath_dir.to_string_lossy())); - Self { cmd, stdin: None } + Self { cmd } } /// Specify where an external library is located. @@ -89,33 +86,10 @@ impl Rustdoc { /// Specify a stdin input pub fn stdin<I: AsRef<[u8]>>(&mut self, input: I) -> &mut Self { - self.cmd.stdin(Stdio::piped()); - self.stdin = Some(input.as_ref().to_vec().into_boxed_slice()); + self.cmd.set_stdin(input.as_ref().to_vec().into_boxed_slice()); self } - /// Get the [`Output`] of the finished process. - #[track_caller] - 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()); - self.cmd.stderr(Stdio::piped()); - - if let Some(input) = &self.stdin { - let mut child = self.cmd.spawn().unwrap(); - - { - let mut stdin = child.stdin.take().unwrap(); - stdin.write_all(input.as_ref()).unwrap(); - } - - child.wait_with_output().expect("failed to get output of finished process") - } else { - self.cmd.output().expect("failed to get output of finished process") - } - } - /// Specify the edition year. pub fn edition(&mut self, edition: &str) -> &mut Self { self.cmd.arg("--edition"); @@ -157,16 +131,4 @@ impl Rustdoc { self.cmd.arg(format); 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.command_output(); - if output.status.code().unwrap() != code { - handle_failed_output(&self.cmd, output, caller_line_number); - } - output - } } diff --git a/src/tools/rust-installer/src/compression.rs b/src/tools/rust-installer/src/compression.rs index 4e840dbfbb4..40c7c597e9b 100644 --- a/src/tools/rust-installer/src/compression.rs +++ b/src/tools/rust-installer/src/compression.rs @@ -214,22 +214,16 @@ impl Write for CombinedEncoder { } fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> { - self.encoders - .par_iter_mut() - .map(|w| w.write_all(buf)) - .collect::<std::io::Result<Vec<()>>>()?; - Ok(()) + self.encoders.par_iter_mut().try_for_each(|w| w.write_all(buf)) } fn flush(&mut self) -> std::io::Result<()> { - self.encoders.par_iter_mut().map(|w| w.flush()).collect::<std::io::Result<Vec<()>>>()?; - Ok(()) + self.encoders.par_iter_mut().try_for_each(Write::flush) } } impl Encoder for CombinedEncoder { fn finish(self: Box<Self>) -> Result<(), Error> { - self.encoders.into_par_iter().map(|e| e.finish()).collect::<Result<Vec<()>, Error>>()?; - Ok(()) + self.encoders.into_par_iter().try_for_each(Encoder::finish) } } diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 2b0dd0062b9..95f1a5d6e1d 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -9,6 +9,7 @@ clap = "4.0.32" env_logger = "0.11" mdbook-trpl-listing = { path = "../../doc/book/packages/mdbook-trpl-listing" } mdbook-trpl-note = { path = "../../doc/book/packages/mdbook-trpl-note" } +mdbook-i18n-helpers = "0.3.3" [dependencies.mdbook] version = "0.4.37" diff --git a/src/tools/rustbook/src/main.rs b/src/tools/rustbook/src/main.rs index 9a06754e4a6..31bba56adde 100644 --- a/src/tools/rustbook/src/main.rs +++ b/src/tools/rustbook/src/main.rs @@ -7,6 +7,7 @@ use clap::{arg, ArgMatches, Command}; use mdbook::errors::Result as Result3; use mdbook::MDBook; +use mdbook_i18n_helpers::preprocessors::Gettext; use mdbook_trpl_listing::TrplListing; use mdbook_trpl_note::TrplNote; @@ -19,6 +20,11 @@ fn main() { .required(false) .value_parser(clap::value_parser!(PathBuf)); + let l_arg = arg!(-l --"lang" <LANGUAGE> +"The output language") + .required(false) + .value_parser(clap::value_parser!(String)); + let dir_arg = arg!([dir] "Root directory for the book\n\ (Defaults to the current directory when omitted)") .value_parser(clap::value_parser!(PathBuf)); @@ -33,6 +39,7 @@ fn main() { Command::new("build") .about("Build the book from the markdown files") .arg(d_arg) + .arg(l_arg) .arg(&dir_arg), ) .subcommand( @@ -63,6 +70,12 @@ pub fn build(args: &ArgMatches) -> Result3<()> { let book_dir = get_book_dir(args); let mut book = load_book(&book_dir)?; + if let Some(lang) = args.get_one::<String>("lang") { + let gettext = Gettext; + book.with_preprocessor(gettext); + book.config.set("book.language", lang).unwrap(); + } + // Set this to allow us to catch bugs in advance. book.config.build.create_missing = false; diff --git a/src/tools/rustc-perf b/src/tools/rustc-perf -Subproject cc81f9654dac3fe08de286907dba747538417af +Subproject 72daa50ce2350f5a9b5ae6dc3ad6babccd14ec0 diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs index 0ddd2c66cf9..bf581279f2a 100644 --- a/src/tools/rustdoc-gui-test/src/main.rs +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -123,9 +123,7 @@ If you want to install the `browser-ui-test` dependency, run `npm install browse cargo.env("RUSTDOCFLAGS", test_props.compile_flags.join(" ")); } - if let Some(flags) = &test_props.run_flags { - cargo.arg(flags); - } + cargo.args(&test_props.run_flags); } if try_run(&mut cargo, config.verbose).is_err() { diff --git a/src/tools/rustdoc-gui/.eslintrc.js b/src/tools/rustdoc-gui/.eslintrc.js index f4aadc07199..3eccbc74cb9 100644 --- a/src/tools/rustdoc-gui/.eslintrc.js +++ b/src/tools/rustdoc-gui/.eslintrc.js @@ -6,7 +6,7 @@ module.exports = { }, "extends": "eslint:recommended", "parserOptions": { - "ecmaVersion": 2018, + "ecmaVersion": 2019, "sourceType": "module" }, "rules": { diff --git a/src/tools/rustdoc-js/.eslintrc.js b/src/tools/rustdoc-js/.eslintrc.js index b9d0e251c24..3eccbc74cb9 100644 --- a/src/tools/rustdoc-js/.eslintrc.js +++ b/src/tools/rustdoc-js/.eslintrc.js @@ -6,7 +6,7 @@ module.exports = { }, "extends": "eslint:recommended", "parserOptions": { - "ecmaVersion": 8, + "ecmaVersion": 2019, "sourceType": "module" }, "rules": { diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs index 3cf133c647c..cbcc0b2d636 100644 --- a/src/tools/rustfmt/src/parse/macros/mod.rs +++ b/src/tools/rustfmt/src/parse/macros/mod.rs @@ -2,7 +2,7 @@ use rustc_ast::token::{Delimiter, NonterminalKind, TokenKind}; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{ast, ptr}; use rustc_parse::parser::{ForceCollect, Parser, Recovery}; -use rustc_parse::{stream_to_parser, MACRO_ARGUMENTS}; +use rustc_parse::MACRO_ARGUMENTS; use rustc_session::parse::ParseSess; use rustc_span::symbol::{self, kw}; use rustc_span::Symbol; @@ -15,7 +15,7 @@ pub(crate) mod cfg_if; pub(crate) mod lazy_static; fn build_stream_parser<'a>(psess: &'a ParseSess, tokens: TokenStream) -> Parser<'a> { - stream_to_parser(psess, tokens, MACRO_ARGUMENTS).recovery(Recovery::Forbidden) + Parser::new(psess, tokens, MACRO_ARGUMENTS).recovery(Recovery::Forbidden) } fn build_parser<'a>(context: &RewriteContext<'a>, tokens: TokenStream) -> Parser<'a> { diff --git a/src/tools/rustfmt/src/parse/parser.rs b/src/tools/rustfmt/src/parse/parser.rs index 5dcdca1d953..6051241309d 100644 --- a/src/tools/rustfmt/src/parse/parser.rs +++ b/src/tools/rustfmt/src/parse/parser.rs @@ -4,7 +4,8 @@ use std::path::{Path, PathBuf}; use rustc_ast::token::TokenKind; use rustc_ast::{ast, attr, ptr}; use rustc_errors::Diag; -use rustc_parse::{new_parser_from_file, parser::Parser as RawParser}; +use rustc_parse::parser::Parser as RawParser; +use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_span::{sym, Span}; use thin_vec::ThinVec; @@ -50,12 +51,9 @@ impl<'a> ParserBuilder<'a> { let parser = match Self::parser(psess.inner(), input) { Ok(p) => p, - Err(db) => { - if let Some(diagnostics) = db { - psess.emit_diagnostics(diagnostics); - return Err(ParserError::ParserCreationError); - } - return Err(ParserError::ParsePanicError); + Err(diagnostics) => { + psess.emit_diagnostics(diagnostics); + return Err(ParserError::ParserCreationError); } }; @@ -65,18 +63,14 @@ impl<'a> ParserBuilder<'a> { fn parser( psess: &'a rustc_session::parse::ParseSess, input: Input, - ) -> Result<rustc_parse::parser::Parser<'a>, Option<Vec<Diag<'a>>>> { + ) -> Result<RawParser<'a>, Vec<Diag<'a>>> { match input { - Input::File(ref file) => catch_unwind(AssertUnwindSafe(move || { - new_parser_from_file(psess, file, None) - })) - .map_err(|_| None), - Input::Text(text) => rustc_parse::maybe_new_parser_from_source_str( + Input::File(ref file) => new_parser_from_file(psess, file, None), + Input::Text(text) => new_parser_from_source_str( psess, rustc_span::FileName::Custom("stdin".to_owned()), text, - ) - .map_err(Some), + ), } } } @@ -111,7 +105,8 @@ impl<'a> Parser<'a> { span: Span, ) -> Result<(ast::AttrVec, ThinVec<ptr::P<ast::Item>>, Span), ParserError> { let result = catch_unwind(AssertUnwindSafe(|| { - let mut parser = new_parser_from_file(psess.inner(), path, Some(span)); + let mut parser = + unwrap_or_emit_fatal(new_parser_from_file(psess.inner(), path, Some(span))); match parser.parse_mod(&TokenKind::Eof) { Ok((a, i, spans)) => Some((a, i, spans.inner_span)), Err(e) => { diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index 09e1dbde1d0..fd59aedadfe 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -111,6 +111,7 @@ pub(crate) fn format_defaultness(defaultness: ast::Defaultness) -> &'static str pub(crate) fn format_safety(unsafety: ast::Safety) -> &'static str { match unsafety { ast::Safety::Unsafe(..) => "unsafe ", + ast::Safety::Safe(..) => "safe ", ast::Safety::Default => "", } } diff --git a/src/tools/rustfmt/tests/source/attrib.rs b/src/tools/rustfmt/tests/source/attrib.rs index fc13cd02b03..d45fba55224 100644 --- a/src/tools/rustfmt/tests/source/attrib.rs +++ b/src/tools/rustfmt/tests/source/attrib.rs @@ -214,8 +214,8 @@ type Os = NoSource; // #3313 fn stmt_expr_attributes() { let foo ; - (#[must_use] - foo) = false ; + #[must_use] + foo = false ; } // #3509 diff --git a/src/tools/rustfmt/tests/target/attrib.rs b/src/tools/rustfmt/tests/target/attrib.rs index 7b3309676de..7e61f68d76a 100644 --- a/src/tools/rustfmt/tests/target/attrib.rs +++ b/src/tools/rustfmt/tests/target/attrib.rs @@ -248,8 +248,8 @@ type Os = NoSource; // #3313 fn stmt_expr_attributes() { let foo; - (#[must_use] - foo) = false; + #[must_use] + foo = false; } // #3509 diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 96a27610500..b07e012a1b8 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -2,7 +2,6 @@ run-make/allocator-shim-circular-deps/Makefile run-make/allow-non-lint-warnings-cmdline/Makefile run-make/archive-duplicate-names/Makefile run-make/atomic-lock-free/Makefile -run-make/bare-outfile/Makefile run-make/branch-protection-check-IBT/Makefile run-make/c-dynamic-dylib/Makefile run-make/c-dynamic-rlib/Makefile @@ -40,7 +39,6 @@ run-make/emit-path-unhashed/Makefile run-make/emit-shared-files/Makefile run-make/emit-stack-sizes/Makefile run-make/emit-to-stdout/Makefile -run-make/emit/Makefile run-make/env-dep-info/Makefile run-make/error-found-staticlib-instead-crate/Makefile run-make/error-writing-dependencies/Makefile @@ -72,7 +70,6 @@ run-make/inaccessible-temp-dir/Makefile run-make/include_bytes_deps/Makefile run-make/incr-add-rust-src-component/Makefile run-make/incr-foreign-head-span/Makefile -run-make/incr-prev-body-beyond-eof/Makefile run-make/incremental-debugger-visualizer/Makefile run-make/incremental-session-fail/Makefile run-make/inline-always-many-cgu/Makefile @@ -125,7 +122,6 @@ run-make/link-framework/Makefile run-make/link-path-order/Makefile run-make/linkage-attr-on-static/Makefile run-make/llvm-ident/Makefile -run-make/llvm-outputs/Makefile run-make/long-linker-command-lines-cmd-exe/Makefile run-make/long-linker-command-lines/Makefile run-make/longjmp-across-rust/Makefile @@ -138,7 +134,6 @@ run-make/lto-readonly-lib/Makefile run-make/lto-smoke-c/Makefile run-make/macos-deployment-target/Makefile run-make/macos-fat-archive/Makefile -run-make/manual-crate-name/Makefile run-make/manual-link/Makefile run-make/many-crates-but-no-match/Makefile run-make/metadata-dep-info/Makefile @@ -147,10 +142,8 @@ run-make/min-global-align/Makefile run-make/mingw-export-call-convention/Makefile run-make/mismatching-target-triples/Makefile run-make/missing-crate-dependency/Makefile -run-make/mixing-formats/Makefile run-make/mixing-libs/Makefile run-make/msvc-opt-minsize/Makefile -run-make/multiple-emits/Makefile run-make/native-link-modifier-bundle/Makefile run-make/native-link-modifier-verbatim-linker/Makefile run-make/native-link-modifier-verbatim-rustc/Makefile @@ -205,7 +198,6 @@ run-make/remap-path-prefix-dwarf/Makefile run-make/remap-path-prefix/Makefile run-make/reproducible-build-2/Makefile run-make/reproducible-build/Makefile -run-make/resolve-rename/Makefile run-make/return-non-c-like-enum-from-c/Makefile run-make/return-non-c-like-enum/Makefile run-make/rlib-chain/Makefile @@ -235,7 +227,6 @@ run-make/static-pie/Makefile run-make/staticlib-blank-lib/Makefile run-make/staticlib-dylib-linkage/Makefile run-make/std-core-cycle/Makefile -run-make/suspicious-library/Makefile run-make/symbol-mangling-hashed/Makefile run-make/symbol-visibility/Makefile run-make/symbols-include-type-name/Makefile diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index efcd2a181ff..2dd3d17f9e3 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -27,7 +27,8 @@ const LICENSES: &[&str] = &[ "MIT OR Zlib OR Apache-2.0", // miniz_oxide "MIT", "MIT/Apache-2.0", - "Unicode-DFS-2016", // tinystr and icu4x + "Unicode-3.0", // icu4x + "Unicode-DFS-2016", // tinystr "Unlicense OR MIT", "Unlicense/MIT", "Zlib OR Apache-2.0 OR MIT", // tinyvec @@ -67,6 +68,7 @@ pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>) //("src/tools/miri/test-cargo-miri", &[], None), // FIXME uncomment once all deps are vendored //("src/tools/miri/test_dependencies", &[], None), // FIXME uncomment once all deps are vendored ("src/tools/rust-analyzer", EXCEPTIONS_RUST_ANALYZER, None), + ("src/tools/rustc-perf", EXCEPTIONS_RUSTC_PERF, None), ("src/tools/x", &[], None), // tidy-alphabetical-end ]; @@ -142,6 +144,22 @@ const EXCEPTIONS_RUST_ANALYZER: ExceptionList = &[ // tidy-alphabetical-end ]; +const EXCEPTIONS_RUSTC_PERF: ExceptionList = &[ + // tidy-alphabetical-start + ("alloc-no-stdlib", "BSD-3-Clause"), + ("alloc-stdlib", "BSD-3-Clause"), + ("brotli", "BSD-3-Clause/MIT"), + ("brotli-decompressor", "BSD-3-Clause/MIT"), + ("encoding_rs", "(Apache-2.0 OR MIT) AND BSD-3-Clause"), + ("inferno", "CDDL-1.0"), + ("instant", "BSD-3-Clause"), + ("ring", NON_STANDARD_LICENSE), // see EXCEPTIONS_NON_STANDARD_LICENSE_DEPS for more. + ("ryu", "Apache-2.0 OR BSL-1.0"), + ("snap", "BSD-3-Clause"), + ("subtle", "BSD-3-Clause"), + // tidy-alphabetical-end +]; + const EXCEPTIONS_CRANELIFT: ExceptionList = &[ // tidy-alphabetical-start ("cranelift-bforest", "Apache-2.0 WITH LLVM-exception"), @@ -178,6 +196,20 @@ const EXCEPTIONS_UEFI_QEMU_TEST: ExceptionList = &[ ("r-efi", "MIT OR Apache-2.0 OR LGPL-2.1-or-later"), // LGPL is not acceptible, but we use it under MIT OR Apache-2.0 ]; +/// Placeholder for non-standard license file. +const NON_STANDARD_LICENSE: &str = "NON_STANDARD_LICENSE"; + +/// These dependencies have non-standard licenses but are genenrally permitted. +const EXCEPTIONS_NON_STANDARD_LICENSE_DEPS: &[&str] = &[ + // `ring` is included because it is an optional dependency of `hyper`, + // which is a training data in rustc-perf for optimized build. + // The license of it is generally `ISC AND MIT AND OpenSSL`, + // though the `package.license` field is not set. + // + // See https://github.com/briansmith/ring/issues/902 + "ring", +]; + /// These are the root crates that are part of the runtime. The licenses for /// these and all their dependencies *must not* be in the exception list. const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", "panic_unwind"]; @@ -411,32 +443,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ // tidy-alphabetical-end ]; -// These crates come from ICU4X and are licensed under the unicode license. -// It currently doesn't have an SPDX identifier, so they cannot put one there. -// See https://github.com/unicode-org/icu4x/pull/3875 -// FIXME: This should be removed once ICU4X crates update. -const ICU4X_UNICODE_LICENSE_DEPENDENCIES: &[&str] = &[ - // tidy-alphabetical-start - "icu_list", - "icu_list_data", - "icu_locid", - "icu_locid_transform", - "icu_locid_transform_data", - "icu_provider", - "icu_provider_adapters", - "icu_provider_macros", - "litemap", - "tinystr", - "writeable", - "yoke", - "yoke-derive", - "zerofrom", - "zerofrom-derive", - "zerovec", - "zerovec-derive", - // tidy-alphabetical-end -]; - const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ // tidy-alphabetical-start "ahash", @@ -610,6 +616,11 @@ fn check_license_exceptions(metadata: &Metadata, exceptions: &[(&str, &str)], ba for pkg in metadata.packages.iter().filter(|p| p.name == *name) { match &pkg.license { None => { + if *license == NON_STANDARD_LICENSE + && EXCEPTIONS_NON_STANDARD_LICENSE_DEPS.contains(&pkg.name.as_str()) + { + continue; + } tidy_error!( bad, "dependency exception `{}` does not declare a license expression", @@ -642,10 +653,6 @@ fn check_license_exceptions(metadata: &Metadata, exceptions: &[(&str, &str)], ba let license = match &pkg.license { Some(license) => license, None => { - if ICU4X_UNICODE_LICENSE_DEPENDENCIES.contains(&pkg.name.as_str()) { - // See the comment on ICU4X_UNICODE_LICENSE_DEPENDENCIES. - continue; - } tidy_error!(bad, "dependency `{}` does not define a license expression", pkg.id); continue; } diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index 40e75d1d3fa..2c97a39f100 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -320,7 +320,7 @@ fn install_requirements( } let stat = Command::new(py_path) - .args(["-m", "pip", "install", "--require-hashes", "-r"]) + .args(["-m", "pip", "install", "--quiet", "--require-hashes", "-r"]) .arg(src_reqs_path) .status()?; if !stat.success() { diff --git a/src/tools/tidy/src/extdeps.rs b/src/tools/tidy/src/extdeps.rs index ff71ca53725..2118de5f204 100644 --- a/src/tools/tidy/src/extdeps.rs +++ b/src/tools/tidy/src/extdeps.rs @@ -4,7 +4,11 @@ use std::fs; use std::path::Path; /// List of allowed sources for packages. -const ALLOWED_SOURCES: &[&str] = &["\"registry+https://github.com/rust-lang/crates.io-index\""]; +const ALLOWED_SOURCES: &[&str] = &[ + r#""registry+https://github.com/rust-lang/crates.io-index""#, + // This is `rust_team_data` used by `site` in src/tools/rustc-perf, + r#""git+https://github.com/rust-lang/team#a5260e76d3aa894c64c56e6ddc8545b9a98043ec""#, +]; /// Checks for external package sources. `root` is the path to the directory that contains the /// workspace `Cargo.toml`. diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 398a6fd0fba..a6ba8959f0c 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2445,7 +2445,6 @@ ui/issues/issue-53300.rs ui/issues/issue-53333.rs ui/issues/issue-53348.rs ui/issues/issue-53419.rs -ui/issues/issue-53498.rs ui/issues/issue-53568.rs ui/issues/issue-5358-1.rs ui/issues/issue-53728.rs diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index cce0fb2c1a2..f2eeda339d8 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -15,7 +15,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: u32 = 900; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1674; +const ISSUES_ENTRY_LIMIT: u32 = 1672; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs index f68b7675c76..63a03834166 100644 --- a/src/tools/tidy/src/walk.rs +++ b/src/tools/tidy/src/walk.rs @@ -16,6 +16,7 @@ pub fn filter_dirs(path: &Path) -> bool { "library/stdarch", "src/tools/cargo", "src/tools/clippy", + "src/tools/libcxx-version", "src/tools/miri", "src/tools/rust-analyzer", "src/tools/rustc-perf", diff --git a/src/version b/src/version index aaceec04e04..dbd41264aa9 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.80.0 +1.81.0 diff --git a/tests/assembly/asm/global_asm.rs b/tests/assembly/asm/global_asm.rs index 8f824563e8a..22cf4bdb15b 100644 --- a/tests/assembly/asm/global_asm.rs +++ b/tests/assembly/asm/global_asm.rs @@ -25,9 +25,9 @@ global_asm!("movl ${}, %ecx", const 5, options(att_syntax)); global_asm!("call {}", sym my_func); // CHECK: lea rax, [rip + MY_STATIC] global_asm!("lea rax, [rip + {}]", sym MY_STATIC); -// CHECK: call _RNvCsddMtV7nAi4C_10global_asm6foobar +// CHECK: call _RNvC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_10global_asm6foobar global_asm!("call {}", sym foobar); -// CHECK: _RNvCsddMtV7nAi4C_10global_asm6foobar: +// CHECK: _RNvC[[CRATE_IDENT]]_10global_asm6foobar: fn foobar() { loop {} } diff --git a/tests/codegen-units/item-collection/generic-impl.rs b/tests/codegen-units/item-collection/generic-impl.rs index 23d09e0d8af..b4cd99272b1 100644 --- a/tests/codegen-units/item-collection/generic-impl.rs +++ b/tests/codegen-units/item-collection/generic-impl.rs @@ -22,16 +22,16 @@ impl<T> Struct<T> { } } -pub struct LifeTimeOnly<'a> { +pub struct _LifeTimeOnly<'a> { _a: &'a u32, } -impl<'a> LifeTimeOnly<'a> { - //~ MONO_ITEM fn LifeTimeOnly::<'_>::foo +impl<'a> _LifeTimeOnly<'a> { + //~ MONO_ITEM fn _LifeTimeOnly::<'_>::foo pub fn foo(&self) {} - //~ MONO_ITEM fn LifeTimeOnly::<'_>::bar + //~ MONO_ITEM fn _LifeTimeOnly::<'_>::bar pub fn bar(&'a self) {} - //~ MONO_ITEM fn LifeTimeOnly::<'_>::baz + //~ MONO_ITEM fn _LifeTimeOnly::<'_>::baz pub fn baz<'b>(&'b self) {} pub fn non_instantiated<T>(&self) {} diff --git a/tests/codegen-units/item-collection/overloaded-operators.rs b/tests/codegen-units/item-collection/overloaded-operators.rs index 69b55695d3d..e00e22dbab9 100644 --- a/tests/codegen-units/item-collection/overloaded-operators.rs +++ b/tests/codegen-units/item-collection/overloaded-operators.rs @@ -5,44 +5,44 @@ use std::ops::{Add, Deref, Index, IndexMut}; -pub struct Indexable { +pub struct _Indexable { data: [u8; 3], } -impl Index<usize> for Indexable { +impl Index<usize> for _Indexable { type Output = u8; - //~ MONO_ITEM fn <Indexable as std::ops::Index<usize>>::index + //~ MONO_ITEM fn <_Indexable as std::ops::Index<usize>>::index fn index(&self, index: usize) -> &Self::Output { if index >= 3 { &self.data[0] } else { &self.data[index] } } } -impl IndexMut<usize> for Indexable { - //~ MONO_ITEM fn <Indexable as std::ops::IndexMut<usize>>::index_mut +impl IndexMut<usize> for _Indexable { + //~ MONO_ITEM fn <_Indexable as std::ops::IndexMut<usize>>::index_mut fn index_mut(&mut self, index: usize) -> &mut Self::Output { if index >= 3 { &mut self.data[0] } else { &mut self.data[index] } } } -//~ MONO_ITEM fn <Equatable as std::cmp::PartialEq>::eq -//~ MONO_ITEM fn <Equatable as std::cmp::PartialEq>::ne +//~ MONO_ITEM fn <_Equatable as std::cmp::PartialEq>::eq +//~ MONO_ITEM fn <_Equatable as std::cmp::PartialEq>::ne #[derive(PartialEq)] -pub struct Equatable(u32); +pub struct _Equatable(u32); -impl Add<u32> for Equatable { +impl Add<u32> for _Equatable { type Output = u32; - //~ MONO_ITEM fn <Equatable as std::ops::Add<u32>>::add + //~ MONO_ITEM fn <_Equatable as std::ops::Add<u32>>::add fn add(self, rhs: u32) -> u32 { self.0 + rhs } } -impl Deref for Equatable { +impl Deref for _Equatable { type Target = u32; - //~ MONO_ITEM fn <Equatable as std::ops::Deref>::deref + //~ MONO_ITEM fn <_Equatable as std::ops::Deref>::deref fn deref(&self) -> &Self::Target { &self.0 } diff --git a/tests/codegen/consts.rs b/tests/codegen/consts.rs index 93c58c37c28..42ce7679d1a 100644 --- a/tests/codegen/consts.rs +++ b/tests/codegen/consts.rs @@ -9,11 +9,11 @@ // CHECK: @STATIC = {{.*}}, align 4 // This checks the constants from inline_enum_const -// CHECK: @alloc_af1f8e8e6f4b341431a1d405e652df2d = {{.*}}, align 2 +// CHECK: @alloc_[[INLINE_ENUM_HASH:[a-f0-9]{32}]] = {{.*}}, align 2 // This checks the constants from {low,high}_align_const, they share the same // constant, but the alignment differs, so the higher one should be used -// CHECK: [[LOW_HIGH:@alloc_[a-f0-9]+]] = {{.*}}, align 4 +// CHECK: [[LOW_HIGH:@alloc_[a-f0-9]{32}]] = {{.*}}, align 4 #[derive(Copy, Clone)] // repr(i16) is required for the {low,high}_align_const test diff --git a/tests/codegen/dont_codegen_private_const_fn_only_used_in_const_eval.rs b/tests/codegen/dont_codegen_private_const_fn_only_used_in_const_eval.rs index eeeaebe52dd..df50b4af809 100644 --- a/tests/codegen/dont_codegen_private_const_fn_only_used_in_const_eval.rs +++ b/tests/codegen/dont_codegen_private_const_fn_only_used_in_const_eval.rs @@ -3,8 +3,25 @@ //@compile-flags: --crate-type=lib -Copt-level=0 +#![feature(generic_const_items)] + const fn foo() {} pub static FOO: () = foo(); // CHECK-NOT: define{{.*}}foo{{.*}} + +const fn bar() {} + +pub const BAR: () = bar(); + +// CHECK-NOT: define{{.*}}bar{{.*}} + +const fn baz() {} + +#[rustfmt::skip] +pub const BAZ<const C: bool>: () = if C { + baz() +}; + +// CHECK: define{{.*}}baz{{.*}} diff --git a/tests/codegen/pattern_type_symbols.rs b/tests/codegen/pattern_type_symbols.rs index dfe83443348..a99b3efca41 100644 --- a/tests/codegen/pattern_type_symbols.rs +++ b/tests/codegen/pattern_type_symbols.rs @@ -15,9 +15,9 @@ fn foo<T>() {} pub fn bar() { // CHECK: call pattern_type_symbols::foo::<u32> - // CHECK: call void @_RINvCs3QvG2ESzx2Q_20pattern_type_symbols3foomEB2_ + // CHECK: call void @_RINvC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_20pattern_type_symbols3foomEB2_ foo::<u32>(); // CHECK: call pattern_type_symbols::foo::<(u32, [(); 0], [(); 999999999], [(); true])> - // CHECK: call void @_RINvCs3QvG2ESzx2Q_20pattern_type_symbols3fooTmAum0_Aum3b9ac9ff_Aub1_EEB2_ + // CHECK: call void @_RINvC[[CRATE_IDENT]]_20pattern_type_symbols3fooTmAum0_Aum3b9ac9ff_Aub1_EEB2_ foo::<NanoU32>(); } diff --git a/tests/codegen/riscv-abi/call-llvm-intrinsics.rs b/tests/codegen/riscv-abi/call-llvm-intrinsics.rs index c3f795e8857..e72a649a530 100644 --- a/tests/codegen/riscv-abi/call-llvm-intrinsics.rs +++ b/tests/codegen/riscv-abi/call-llvm-intrinsics.rs @@ -23,7 +23,7 @@ pub fn do_call() { unsafe { // Ensure that we `call` LLVM intrinsics instead of trying to `invoke` them - // CHECK: store float 4.000000e+00, float* %{{.}}, align 4 + // CHECK: store float 4.000000e+00, ptr %{{.}}, align 4 // CHECK: call float @llvm.sqrt.f32(float %{{.}} sqrt(4.0); } diff --git a/tests/codegen/riscv-abi/riscv64-lp64d-abi.rs b/tests/codegen/riscv-abi/riscv64-lp64d-abi.rs index 060d91a2696..bcd9b0eae71 100644 --- a/tests/codegen/riscv-abi/riscv64-lp64d-abi.rs +++ b/tests/codegen/riscv-abi/riscv64-lp64d-abi.rs @@ -1,10 +1,19 @@ -// -//@ compile-flags: -C no-prepopulate-passes -//@ only-riscv64 -//@ only-linux +//@ compile-flags: -O -C no-prepopulate-passes --target riscv64gc-unknown-linux-gnu +//@ needs-llvm-components: riscv + +#![feature(no_core, lang_items)] #![crate_type = "lib"] +#![no_std] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "freeze"] +trait Freeze {} +#[lang = "copy"] +trait Copy {} -// CHECK: define void @f_fpr_tracking(double %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, i8 zeroext %i) +// CHECK: define void @f_fpr_tracking(double %0, double %1, double %2, double %3, double %4, double %5, double %6, double %7, i8 noundef zeroext %i) #[no_mangle] pub extern "C" fn f_fpr_tracking( a: f64, @@ -144,7 +153,7 @@ pub extern "C" fn f_ret_double_int64_s() -> DoubleInt64 { DoubleInt64 { f: 1., i: 2 } } -// CHECK: define void @f_double_int8_s_arg_insufficient_gprs(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 signext %h, [2 x i64] %0) +// CHECK: define void @f_double_int8_s_arg_insufficient_gprs(i32 noundef signext %a, i32 noundef signext %b, i32 noundef signext %c, i32 noundef signext %d, i32 noundef signext %e, i32 noundef signext %f, i32 noundef signext %g, i32 noundef signext %h, [2 x i64] %0) #[no_mangle] pub extern "C" fn f_double_int8_s_arg_insufficient_gprs( a: i32, @@ -250,11 +259,11 @@ pub struct IntDoubleInt { c: i32, } -// CHECK: define void @f_int_double_int_s_arg(%IntDoubleInt* {{.*}}%a) +// CHECK: define void @f_int_double_int_s_arg(ptr {{.*}} %a) #[no_mangle] pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {} -// CHECK: define void @f_ret_int_double_int_s(%IntDoubleInt* {{.*}}sret +// CHECK: define void @f_ret_int_double_int_s(ptr {{.*}} sret([24 x i8]) align 8 dereferenceable(24) %_0) #[no_mangle] pub extern "C" fn f_ret_int_double_int_s() -> IntDoubleInt { IntDoubleInt { a: 1, b: 2., c: 3 } diff --git a/tests/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs b/tests/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs index 3d0512817f7..27018d2e6d2 100644 --- a/tests/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs +++ b/tests/codegen/riscv-abi/riscv64-lp64f-lp64d-abi.rs @@ -1,10 +1,19 @@ -// -//@ compile-flags: -C no-prepopulate-passes -//@ only-riscv64 -//@ only-linux +//@ compile-flags: -O -C no-prepopulate-passes --target riscv64gc-unknown-linux-gnu +//@ needs-llvm-components: riscv + +#![feature(no_core, lang_items)] #![crate_type = "lib"] +#![no_std] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "freeze"] +trait Freeze {} +#[lang = "copy"] +trait Copy {} -// CHECK: define void @f_fpr_tracking(float %0, float %1, float %2, float %3, float %4, float %5, float %6, float %7, i8 zeroext %i) +// CHECK: define void @f_fpr_tracking(float %0, float %1, float %2, float %3, float %4, float %5, float %6, float %7, i8 noundef zeroext %i) #[no_mangle] pub extern "C" fn f_fpr_tracking( a: f32, @@ -128,7 +137,7 @@ pub extern "C" fn f_ret_float_int64_s() -> FloatInt64 { FloatInt64 { f: 1., i: 2 } } -// CHECK: define void @f_float_int8_s_arg_insufficient_gprs(i32 signext %a, i32 signext %b, i32 signext %c, i32 signext %d, i32 signext %e, i32 signext %f, i32 signext %g, i32 signext %h, i64 %0) +// CHECK: define void @f_float_int8_s_arg_insufficient_gprs(i32 noundef signext %a, i32 noundef signext %b, i32 noundef signext %c, i32 noundef signext %d, i32 noundef signext %e, i32 noundef signext %f, i32 noundef signext %g, i32 noundef signext %h, i64 %0) #[no_mangle] pub extern "C" fn f_float_int8_s_arg_insufficient_gprs( a: i32, diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs index 4e5ad8ad4a9..9870ecc69ba 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs @@ -82,9 +82,9 @@ pub fn foo12(_: &Type4, _: &Type4, _: &Type4) {} // CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooEE"} // CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_E"} // CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_S0_E"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooEE"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooES0_E"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo3FooES0_S0_E"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooEE"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_E"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_S0_E"} // CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barEE"} // CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_E"} // CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_S0_E"} diff --git a/tests/codegen/simd/packed-simd.rs b/tests/codegen/simd/packed-simd.rs index f0911b6e360..1df09c96e6c 100644 --- a/tests/codegen/simd/packed-simd.rs +++ b/tests/codegen/simd/packed-simd.rs @@ -9,10 +9,11 @@ use core::intrinsics::simd as intrinsics; use core::{mem, ptr}; // Test codegen for not only "packed" but also "fully aligned" SIMD types, and conversion between -// A repr(packed,simd) type with 3 elements can't exceed its element alignment, -// whereas the same type as repr(simd) will instead have padding. +// them. A repr(packed,simd) type with 3 elements can't exceed its element alignment, whereas the +// same type as repr(simd) will instead have padding. #[repr(simd, packed)] +#[derive(Copy, Clone)] pub struct Simd<T, const N: usize>([T; N]); #[repr(simd)] @@ -28,11 +29,11 @@ fn load<T, const N: usize>(v: Simd<T, N>) -> FullSimd<T, N> { } } -// CHECK-LABEL: square_packed +// CHECK-LABEL: square_packed_full // CHECK-SAME: ptr{{[a-z_ ]*}} sret([[RET_TYPE:[^)]+]]) [[RET_ALIGN:align (8|16)]]{{[^%]*}} [[RET_VREG:%[_0-9]*]] // CHECK-SAME: ptr{{[a-z_ ]*}} align 4 #[no_mangle] -pub fn square_packed(x: Simd<f32, 3>) -> FullSimd<f32, 3> { +pub fn square_packed_full(x: Simd<f32, 3>) -> FullSimd<f32, 3> { // CHECK-NEXT: start // noopt: alloca [[RET_TYPE]], [[RET_ALIGN]] // CHECK: load <3 x float> @@ -42,3 +43,17 @@ pub fn square_packed(x: Simd<f32, 3>) -> FullSimd<f32, 3> { // CHECK-NEXT: ret void unsafe { intrinsics::simd_mul(x, x) } } + +// CHECK-LABEL: square_packed +// CHECK-SAME: ptr{{[a-z_ ]*}} sret([[RET_TYPE:[^)]+]]) [[RET_ALIGN:align 4]]{{[^%]*}} [[RET_VREG:%[_0-9]*]] +// CHECK-SAME: ptr{{[a-z_ ]*}} align 4 +#[no_mangle] +pub fn square_packed(x: Simd<f32, 3>) -> Simd<f32, 3> { + // CHECK-NEXT: start + // CHECK-NEXT: load <3 x float> + // noopt-NEXT: load <3 x float> + // CHECK-NEXT: [[VREG:%[a-z0-9_]+]] = fmul <3 x float> + // CHECK-NEXT: store <3 x float> [[VREG]], ptr [[RET_VREG]], [[RET_ALIGN]] + // CHECK-NEXT: ret void + unsafe { intrinsics::simd_mul(x, x) } +} diff --git a/tests/codegen/virtual-function-elimination.rs b/tests/codegen/virtual-function-elimination.rs index 6c391d9114b..23d7657baa9 100644 --- a/tests/codegen/virtual-function-elimination.rs +++ b/tests/codegen/virtual-function-elimination.rs @@ -81,7 +81,7 @@ fn taking_u(u: &dyn U) -> i32 { } pub fn taking_v(v: &dyn V) -> i32 { - // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"NtCs64ITQYi9761_28virtual_function_elimination1V") + // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"NtC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_28virtual_function_elimination1V") v.public_function() } @@ -96,5 +96,5 @@ pub fn main() { // CHECK: ![[TYPE0]] = !{i64 0, !"[[MANGLED_TYPE0]]"} // CHECK: ![[VCALL_VIS0]] = !{i64 2} // CHECK: ![[TYPE1]] = !{i64 0, !"[[MANGLED_TYPE1]]"} -// CHECK: ![[TYPE2]] = !{i64 0, !"NtCs64ITQYi9761_28virtual_function_elimination1V"} +// CHECK: ![[TYPE2]] = !{i64 0, !"NtC[[CRATE_IDENT]]_28virtual_function_elimination1V"} // CHECK: ![[VCALL_VIS2]] = !{i64 1} diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map index fd8fbd9fa75..156947f4e21 100644 --- a/tests/coverage/closure_macro.cov-map +++ b/tests/coverage/closure_macro.cov-map @@ -7,16 +7,14 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 29, 1) to (start + 2, 2) Function name: closure_macro::main -Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 21, 01, 01, 21, 02, 02, 09, 00, 12, 02, 00, 0f, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 21, 01, 01, 21, 02, 02, 09, 00, 0f, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 6 +Number of file 0 mappings: 5 - Code(Counter(0)) at (prev + 33, 1) to (start + 1, 33) -- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 18) - = (c0 - c1) -- Code(Expression(0, Sub)) at (prev + 0, 15) to (start + 0, 84) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) = (c0 - c1) - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11) diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map index 43b52008f33..0f2b4e01748 100644 --- a/tests/coverage/closure_macro_async.cov-map +++ b/tests/coverage/closure_macro_async.cov-map @@ -15,16 +15,14 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 35, 1) to (start + 0, 43) Function name: closure_macro_async::test::{closure#0} -Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 23, 2b, 01, 21, 02, 02, 09, 00, 12, 02, 00, 0f, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 23, 2b, 01, 21, 02, 02, 09, 00, 0f, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 6 +Number of file 0 mappings: 5 - Code(Counter(0)) at (prev + 35, 43) to (start + 1, 33) -- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 18) - = (c0 - c1) -- Code(Expression(0, Sub)) at (prev + 0, 15) to (start + 0, 84) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) = (c0 - c1) - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11) diff --git a/tests/crashes/119830.rs b/tests/crashes/119830.rs deleted file mode 100644 index 71becc04e16..00000000000 --- a/tests/crashes/119830.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #119830 -#![feature(effects)] -#![feature(min_specialization)] - -trait Specialize {} - -trait Foo {} - -impl<T> const Foo for T {} - -impl<T> const Foo for T where T: const Specialize {} diff --git a/tests/crashes/121134.rs b/tests/crashes/121134.rs deleted file mode 100644 index 36397d4ec3c..00000000000 --- a/tests/crashes/121134.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ known-bug: #121134 -trait Output<'a> { - type Type; -} - -struct Wrapper; - -impl Wrapper { - fn do_something_wrapper<O, F>(&mut self, do_something_wrapper: F) - where - FnOnce:, - F: for<'a> FnOnce(<F as Output<i32, _>>::Type), - { - } -} - -fn main() { - let mut wrapper = Wrapper; - wrapper.do_something_wrapper::<i32, _>(|value| ()); -} diff --git a/tests/crashes/122908.rs b/tests/crashes/122908.rs deleted file mode 100644 index c9da1bc1879..00000000000 --- a/tests/crashes/122908.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #122908 -trait Trait<const module_path: Trait = bar> { - async fn handle<F>(slf: &F) {} -} diff --git a/tests/crashes/123917.rs b/tests/crashes/123917.rs deleted file mode 100644 index 66e75460662..00000000000 --- a/tests/crashes/123917.rs +++ /dev/null @@ -1,41 +0,0 @@ -//@ known-bug: #123917 -//@ compile-flags: -Zmir-opt-level=5 -Zpolymorphize=on - -use std::marker::PhantomData; - -pub struct Id<'id>(); - -pub struct Item<'life, T> { - data: T, -} - -pub struct Token<'life, 'borrow, 'compact, 'reborrow, T> -where - 'life: 'reborrow, - T: Tokenize, -{ - ptr: *mut <T as Tokenize>::Tokenized, - ptr: core::ptr::NonNull<T::Tokenized>, - _phantom: PhantomData<Id<'life>>, -} - -impl<'life> Arena<'life> { - pub fn tokenize<'before, 'compact, 'borrow, 'reborrow, T, U>( - item: Item<'life, &'before mut T>, - ) -> Token<'life, 'borrow, 'compact, 'reborrow, U> - where - T: Tokenize<'life, 'borrow, 'compact, 'reborrow, Untokenized = U>, - T::Untokenized: Tokenize<'life, 'borrow, 'compact, 'reborrow>, - { - let dst = item.data as *mut T as *mut T::Tokenized; - Token { - ptr: core::ptr::NonNull::new(dst as *mut _).unwrap(), - _phantom: PhantomData, - } - } -} - -pub trait Tokenize { - type Tokenized; - type Untokenized; -} diff --git a/tests/crashes/124342.rs b/tests/crashes/124342.rs deleted file mode 100644 index ae51b3db96f..00000000000 --- a/tests/crashes/124342.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: #124342 -trait Trait2 : Trait { - reuse <() as Trait>::async { - (async || {}).await; - }; -} diff --git a/tests/crashes/124347.rs b/tests/crashes/124347.rs deleted file mode 100644 index d2bc555fe1c..00000000000 --- a/tests/crashes/124347.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ known-bug: #124347 -trait Trait: ToReuse { - reuse Trait::lolno { &self.0 }; -} diff --git a/tests/crashes/124490.rs b/tests/crashes/124490.rs deleted file mode 100644 index 9f605c32cf2..00000000000 --- a/tests/crashes/124490.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ 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 deleted file mode 100644 index 5320ce27843..00000000000 --- a/tests/crashes/124552.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ 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/125013-1.rs b/tests/crashes/125013-1.rs deleted file mode 100644 index ae66d7a1466..00000000000 --- a/tests/crashes/125013-1.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ known-bug: rust-lang/rust#125013 -//@ edition:2021 -use io::{self as std}; -use std::ops::Deref::{self as io}; -pub fn main() {} diff --git a/tests/crashes/125013-2.rs b/tests/crashes/125013-2.rs deleted file mode 100644 index a14c8a76b63..00000000000 --- a/tests/crashes/125013-2.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: rust-lang/rust#125013 -//@ edition:2021 -mod a { - pub mod b { - pub mod c { - pub trait D {} - } - } -} - -use a::*; - -use e as b; -use b::c::D as e; - -fn main() { } diff --git a/tests/crashes/125556.rs b/tests/crashes/125556.rs deleted file mode 100644 index f2e2a991b11..00000000000 --- a/tests/crashes/125556.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ known-bug: rust-lang/rust#125556 -//@ compile-flags: -Znext-solver=coherence - -#![feature(generic_const_exprs)] - -pub struct A<const z: [usize; x]> {} - -impl A<2> { - pub const fn B() {} -} - -impl A<2> { - pub const fn B() {} -} diff --git a/tests/crashes/125655.rs b/tests/crashes/125655.rs new file mode 100644 index 00000000000..fbf92ca22be --- /dev/null +++ b/tests/crashes/125655.rs @@ -0,0 +1,8 @@ +//@ known-bug: rust-lang/rust#125655 + +fn main() { + static foo: dyn Fn() -> u32 = || -> u32 { + ... + 0 + }; +} diff --git a/tests/crashes/125680.rs b/tests/crashes/125680.rs new file mode 100644 index 00000000000..09f4f318bdd --- /dev/null +++ b/tests/crashes/125680.rs @@ -0,0 +1,15 @@ +//@ known-bug: rust-lang/rust#125680 +//@ edition:2021 + +#![feature(generic_const_exprs)] + +use core::fmt::Debug; + +struct Inline<T> +where + [(); std::mem::offset_of!((T,), 0)]:, +{} + +fn main() { + let dst = Inline::<dyn Debug>::new(0); // BANG! +} diff --git a/tests/crashes/125758.rs b/tests/crashes/125758.rs new file mode 100644 index 00000000000..86c3b80abab --- /dev/null +++ b/tests/crashes/125758.rs @@ -0,0 +1,26 @@ +//@ known-bug: rust-lang/rust#125758 +#![feature(impl_trait_in_assoc_type)] + +trait Trait: Sized { + type Assoc2; +} + +impl Trait for Bar { + type Assoc2 = impl std::fmt::Debug; +} + +struct Foo { + field: <Bar as Trait>::Assoc2, +} + +enum Bar { + C = 42, + D = 99, +} + +static BAR: u8 = 42; + +static FOO2: (&Foo, &<Bar as Trait>::Assoc2) = + unsafe { (std::mem::transmute(&BAR), std::mem::transmute(&BAR)) }; + +fn main() {} diff --git a/tests/crashes/125768.rs b/tests/crashes/125768.rs new file mode 100644 index 00000000000..3c04431baa0 --- /dev/null +++ b/tests/crashes/125768.rs @@ -0,0 +1,15 @@ +//@ known-bug: rust-lang/rust#125768 + +#![feature(generic_const_exprs)] + +struct Outer<const A: i64, const B: usize>(); +impl<const A: usize, const B: usize> Outer<A, B> +where + [(); A + (B * 2)]:, +{ + fn o() -> Union {} +} + +fn main() { + Outer::<1, 1>::o(); +} diff --git a/tests/crashes/125769.rs b/tests/crashes/125769.rs new file mode 100644 index 00000000000..da19458f7ca --- /dev/null +++ b/tests/crashes/125769.rs @@ -0,0 +1,14 @@ +//@ known-bug: rust-lang/rust#125769 + +#![feature(generic_const_exprs)] + +trait Trait {} + +struct HasCastInTraitImpl<const N: usize, const M: u128>; +impl<const O: f64> Trait for HasCastInTraitImpl<O, { O as u128 }> {} + +pub fn use_trait_impl() { + fn assert_impl<T: Trait>() {} + + assert_impl::<HasCastInTraitImpl<13, 13>>(); +} diff --git a/tests/crashes/125772.rs b/tests/crashes/125772.rs new file mode 100644 index 00000000000..2965cfc9e7c --- /dev/null +++ b/tests/crashes/125772.rs @@ -0,0 +1,17 @@ +//@ known-bug: rust-lang/rust#125772 +//@ only-x86_64 +#![feature(generic_const_exprs)] + +struct Outer<const A: i64, const B: i64>(); +impl<const A: usize, const B: usize> Outer<A, B> +where + [(); A + (B * 2)]:, +{ + fn i() -> Self { + Self + } +} + +fn main() { + Outer::<1, 1>::o(); +} diff --git a/tests/crashes/125799.rs b/tests/crashes/125799.rs new file mode 100644 index 00000000000..62d5438b4e4 --- /dev/null +++ b/tests/crashes/125799.rs @@ -0,0 +1,22 @@ +//@ known-bug: rust-lang/rust#125799 +//@ only-x86_64 + +trait Trait<T> { + type Assoc; +} + +impl<T> Trait<T> for Vec<T> { + type Assoc = (); +} + +impl Trait<u8> for Vec<u8> {} + +const BAR: <Vec<u8> as Trait<u8>>::Assoc = 3; + +pub fn main() { + let x: isize = 3; + let _ = match x { + BAR => 2, + _ => 3, + }; +} diff --git a/tests/crashes/125801.rs b/tests/crashes/125801.rs new file mode 100644 index 00000000000..aaa76bd0ba6 --- /dev/null +++ b/tests/crashes/125801.rs @@ -0,0 +1,20 @@ +//@ known-bug: rust-lang/rust#125801 + +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +trait Foo { + type Output; +} + +impl Foo for [u8; 3] { + type Output = [u8; 3]; +} + +static A: <[u8; N] as Foo>::Output = [1, 2, 3]; + +fn main() { + || { + let _ = A[1]; + }; +} diff --git a/tests/crashes/125810.rs b/tests/crashes/125810.rs new file mode 100644 index 00000000000..4a152da8ddf --- /dev/null +++ b/tests/crashes/125810.rs @@ -0,0 +1,10 @@ +//@ known-bug: rust-lang/rust#125810 +#![feature(arbitrary_self_types, dispatch_from_dyn)] + +use std::ops::{Deref, DispatchFromDyn}; + +trait Trait<T: Deref<Target = Self> + DispatchFromDyn<T>> { + fn MONO_BUF(self: T) -> dyn Trait<T>; +} + +fn main() {} diff --git a/tests/crashes/125811.rs b/tests/crashes/125811.rs new file mode 100644 index 00000000000..eb764e8d152 --- /dev/null +++ b/tests/crashes/125811.rs @@ -0,0 +1,34 @@ +//@ known-bug: rust-lang/rust#125811 +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + + pub fn is_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src>, + { + } +} + +#[repr(C)] +struct Zst; + +enum V0 { + B(!), +} + +enum V2 { + V = 2, +} + +enum Lopsided { + Smol(Zst), + Lorg(V0), +} + +#[repr(C)] +#[repr(C)] +struct Dst(Lopsided, V2); + +fn should_pad_variants() { + assert::is_transmutable::<Src, Dst>(); +} diff --git a/tests/crashes/125841.rs b/tests/crashes/125841.rs new file mode 100644 index 00000000000..e2e61071f1d --- /dev/null +++ b/tests/crashes/125841.rs @@ -0,0 +1,14 @@ +//@ known-bug: rust-lang/rust#125841 +#![feature(non_lifetime_binders)] +fn take(id: impl for<T> Fn(T) -> T) { + id(0); + id(""); +} + +fn take2() -> impl for<T> Fn(T) -> T { + |x| x +} + +fn main() { + take(|x| take2) +} diff --git a/tests/crashes/125843.rs b/tests/crashes/125843.rs new file mode 100644 index 00000000000..8b9a3913c7e --- /dev/null +++ b/tests/crashes/125843.rs @@ -0,0 +1,4 @@ +//@ known-bug: rust-lang/rust#125843 +#![feature(non_lifetime_binders)] +trait v0<> {} +fn kind :(v3main impl for<v4> v0<'_, v2 = impl v0<v4> + '_>) {} diff --git a/tests/crashes/125874.rs b/tests/crashes/125874.rs new file mode 100644 index 00000000000..6a2713cd7c8 --- /dev/null +++ b/tests/crashes/125874.rs @@ -0,0 +1,22 @@ +//@ known-bug: rust-lang/rust#125874 +pub trait A {} + +pub trait Mirror { + type Assoc: ?Sized; +} +impl<T: ?Sized> Mirror for dyn A { + type Assoc = T; +} + +struct Bar { + foo: <dyn A + 'static as Mirror>::Assoc, +} + +pub fn main() { + let strct = Bar { foo: 3 }; + + match strct { + Bar { foo: 1, .. } => {} + _ => (), + }; +} diff --git a/tests/crashes/125879.rs b/tests/crashes/125879.rs new file mode 100644 index 00000000000..4318842e455 --- /dev/null +++ b/tests/crashes/125879.rs @@ -0,0 +1,18 @@ +//@ known-bug: rust-lang/rust#125879 +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +pub type PubAlias0 = PubTy::PrivAssocTy; + +pub struct PubTy; +impl PubTy { + type PrivAssocTy = (); +} + +pub struct S(pub PubAlias0); + +pub unsafe fn foo(a: S) -> S { + a +} + +fn main() {} diff --git a/tests/crashes/125881.rs b/tests/crashes/125881.rs new file mode 100644 index 00000000000..98331d3c974 --- /dev/null +++ b/tests/crashes/125881.rs @@ -0,0 +1,8 @@ +//@ known-bug: rust-lang/rust#125881 +#![crate_type = "lib"] +#![feature(transmutability)] +#![feature(unboxed_closures,effects)] + +const fn test() -> impl std::mem::BikeshedIntrinsicFrom() { + || {} +} diff --git a/tests/crashes/125888.rs b/tests/crashes/125888.rs new file mode 100644 index 00000000000..ae8f2d6576b --- /dev/null +++ b/tests/crashes/125888.rs @@ -0,0 +1,17 @@ +//@ known-bug: rust-lang/rust#125888 +enum NestedEnum { + First, + Second, +} + +enum Enum { + Variant(*const &'a ()), +} + +fn foo(x: Enum) { + match x { + Enum::Variant(NestedEnum::Second) => {} + } +} + +fn main() {} diff --git a/tests/crashes/125914.rs b/tests/crashes/125914.rs new file mode 100644 index 00000000000..77ccb9fb097 --- /dev/null +++ b/tests/crashes/125914.rs @@ -0,0 +1,20 @@ +//@ known-bug: rust-lang/rust#125914 +enum AstKind<'ast> { + ExprInt, +} + +enum Foo { + Bar(isize), + Baz, +} + +enum Other { + Other1(Foo), + Other2(AstKind), +} + +fn main() { + match Other::Other1(Foo::Baz) { + ::Other::Other2(::Foo::Bar(..)) => {} + } +} diff --git a/tests/crashes/125957.rs b/tests/crashes/125957.rs new file mode 100644 index 00000000000..e3abe5262eb --- /dev/null +++ b/tests/crashes/125957.rs @@ -0,0 +1,20 @@ +//@ known-bug: rust-lang/rust#125957 +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] +#![feature(associated_const_equality)] + +pub struct Equal<const T: usize, const R: usize>(); + +pub enum ParseMode { + Raw, +} +pub trait Parse { + const PARSE_MODE: ParseMode; +} +pub trait RenderRaw: Parse<PARSE_MODE = { ParseMode::Raw }> {} + +trait GenericVec<T> { + fn unwrap() -> dyn RenderRaw; +} + +fn main() {} diff --git a/tests/crashes/125992.rs b/tests/crashes/125992.rs new file mode 100644 index 00000000000..d78f28ce6de --- /dev/null +++ b/tests/crashes/125992.rs @@ -0,0 +1,19 @@ +//@ known-bug: rust-lang/rust#125992 +//@ compile-flags: -Zpolonius=next + +#![feature(inherent_associated_types)] + +type Function = for<'a> fn(&'a i32) -> S<'a>::P; + +struct S<'a>(&'a ()); + +impl<'a> S { + type P = &'a i32; +} + +fn ret_ref_local<'e>() -> &'e i32 { + let f: Function = |x| x; + + let local = 0; + f(&local) +} diff --git a/tests/debuginfo/function-names.rs b/tests/debuginfo/function-names.rs index 2b0c2593676..d9b61e73621 100644 --- a/tests/debuginfo/function-names.rs +++ b/tests/debuginfo/function-names.rs @@ -37,7 +37,7 @@ // Const generic parameter // gdb-command:info functions -q function_names::const_generic_fn.* // gdb-check:[...]static fn function_names::const_generic_fn_bool<false>(); -// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#ad91263f6d2dd96e}>(); +// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#a70c39591cb5f53d}>(); // gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>(); // gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>(); @@ -76,9 +76,6 @@ // Const generic parameter // cdb-command:x a!function_names::const_generic_fn* // cdb-check:[...] a!function_names::const_generic_fn_bool<false> (void) -// cdb-check:[...] a!function_names::const_generic_fn_non_int<CONST$ad91263f6d2dd96e> (void) -// cdb-check:[...] a!function_names::const_generic_fn_unsigned_int<14> (void) -// cdb-check:[...] a!function_names::const_generic_fn_signed_int<-7> (void) #![allow(unused_variables)] #![feature(omit_gdb_pretty_printer_section)] diff --git a/tests/mir-opt/address_of.rs b/tests/mir-opt/address_of.rs index 57a317a4a90..164ab38ebe7 100644 --- a/tests/mir-opt/address_of.rs +++ b/tests/mir-opt/address_of.rs @@ -9,7 +9,7 @@ fn address_of_reborrow() { y as *const [i32; 10]; y as *const dyn Send; y as *const [i32]; - y as *const i32; // This is a cast, not a coercion + y as *const i32; // This is a cast, not a coercion let p: *const _ = y; let p: *const [i32; 10] = y; diff --git a/tests/mir-opt/array_index_is_temporary.rs b/tests/mir-opt/array_index_is_temporary.rs index cd44c31d000..771fb3771b5 100644 --- a/tests/mir-opt/array_index_is_temporary.rs +++ b/tests/mir-opt/array_index_is_temporary.rs @@ -9,7 +9,6 @@ unsafe fn foo(z: *mut usize) -> u32 { 99 } - // EMIT_MIR array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.mir fn main() { // CHECK-LABEL: fn main( diff --git a/tests/mir-opt/building/custom/aggregate_exprs.rs b/tests/mir-opt/building/custom/aggregate_exprs.rs index d581886247f..8985f106817 100644 --- a/tests/mir-opt/building/custom/aggregate_exprs.rs +++ b/tests/mir-opt/building/custom/aggregate_exprs.rs @@ -7,18 +7,18 @@ use core::intrinsics::mir::*; // EMIT_MIR aggregate_exprs.tuple.built.after.mir #[custom_mir(dialect = "built")] fn tuple() -> (i32, bool) { - mir!( + mir! { { RET = (1, true); Return() } - ) + } } // EMIT_MIR aggregate_exprs.array.built.after.mir #[custom_mir(dialect = "built")] fn array() -> [i32; 2] { - mir!( + mir! { let x: [i32; 2]; let one: i32; { @@ -28,7 +28,7 @@ fn array() -> [i32; 2] { RET = Move(x); Return() } - ) + } } struct Foo { @@ -48,7 +48,7 @@ union Onion { // EMIT_MIR aggregate_exprs.adt.built.after.mir #[custom_mir(dialect = "built")] fn adt() -> Onion { - mir!( + mir! { let one: i32; let x: Foo; let y: Bar; @@ -62,7 +62,7 @@ fn adt() -> Onion { RET = Onion { neon: Field(Variant(y, 0), 1) }; Return() } - ) + } } fn main() { diff --git a/tests/mir-opt/building/custom/arbitrary_let.rs b/tests/mir-opt/building/custom/arbitrary_let.rs index f8ee8504e32..3f251cd81bc 100644 --- a/tests/mir-opt/building/custom/arbitrary_let.rs +++ b/tests/mir-opt/building/custom/arbitrary_let.rs @@ -8,7 +8,7 @@ use core::ptr::{addr_of, addr_of_mut}; // EMIT_MIR arbitrary_let.arbitrary_let.built.after.mir #[custom_mir(dialect = "built")] fn arbitrary_let(x: i32) -> i32 { - mir!( + mir! { { let y = x; Goto(second) @@ -21,7 +21,7 @@ fn arbitrary_let(x: i32) -> i32 { let z = y; Goto(third) } - ) + } } fn main() { diff --git a/tests/mir-opt/building/custom/arrays.rs b/tests/mir-opt/building/custom/arrays.rs index e9a53b7aacb..4bd6f93e113 100644 --- a/tests/mir-opt/building/custom/arrays.rs +++ b/tests/mir-opt/building/custom/arrays.rs @@ -7,12 +7,14 @@ use core::intrinsics::mir::*; // EMIT_MIR arrays.arrays.built.after.mir #[custom_mir(dialect = "built")] fn arrays<const C: usize>() -> usize { - mir!({ - let x = [5_i32; C]; - let c = Len(x); - RET = c; - Return() - }) + mir! { + { + let x = [5_i32; C]; + let c = Len(x); + RET = c; + Return() + } + } } fn main() { diff --git a/tests/mir-opt/building/custom/as_cast.rs b/tests/mir-opt/building/custom/as_cast.rs index 92aea64db07..908d378771d 100644 --- a/tests/mir-opt/building/custom/as_cast.rs +++ b/tests/mir-opt/building/custom/as_cast.rs @@ -7,34 +7,34 @@ use core::intrinsics::mir::*; // EMIT_MIR as_cast.int_to_int.built.after.mir #[custom_mir(dialect = "built")] fn int_to_int(x: u32) -> i32 { - mir!( + mir! { { RET = x as i32; Return() } - ) + } } // EMIT_MIR as_cast.float_to_int.built.after.mir #[custom_mir(dialect = "built")] fn float_to_int(x: f32) -> i32 { - mir!( + mir! { { RET = x as i32; Return() } - ) + } } // EMIT_MIR as_cast.int_to_ptr.built.after.mir #[custom_mir(dialect = "built")] fn int_to_ptr(x: usize) -> *const i32 { - mir!( + mir! { { RET = x as *const i32; Return() } - ) + } } fn main() { diff --git a/tests/mir-opt/building/custom/assume.rs b/tests/mir-opt/building/custom/assume.rs index a477e12f0e0..4a55617136a 100644 --- a/tests/mir-opt/building/custom/assume.rs +++ b/tests/mir-opt/building/custom/assume.rs @@ -7,34 +7,34 @@ use core::intrinsics::mir::*; // EMIT_MIR assume.assume_local.built.after.mir #[custom_mir(dialect = "built")] fn assume_local(x: bool) { - mir!( + mir! { { Assume(x); Return() } - ) + } } // EMIT_MIR assume.assume_place.built.after.mir #[custom_mir(dialect = "built")] fn assume_place(p: (bool, u8)) { - mir!( + mir! { { Assume(p.0); Return() } - ) + } } // EMIT_MIR assume.assume_constant.built.after.mir #[custom_mir(dialect = "built")] fn assume_constant() { - mir!( + mir! { { Assume(true); Return() } - ) + } } fn main() { diff --git a/tests/mir-opt/building/custom/composite_return.rs b/tests/mir-opt/building/custom/composite_return.rs index 33c903fa0f8..0cf2cc8d189 100644 --- a/tests/mir-opt/building/custom/composite_return.rs +++ b/tests/mir-opt/building/custom/composite_return.rs @@ -7,14 +7,14 @@ use core::intrinsics::mir::*; // EMIT_MIR composite_return.tuple.built.after.mir #[custom_mir(dialect = "runtime", phase = "optimized")] fn tuple() -> (i32, bool) { - mir!( + mir! { type RET = (i32, bool); { RET.0 = 1; RET.1 = true; Return() } - ) + } } fn main() { diff --git a/tests/mir-opt/building/custom/consts.consts.built.after.mir b/tests/mir-opt/building/custom/consts.consts.built.after.mir index 7b6964849d4..a011fadcef1 100644 --- a/tests/mir-opt/building/custom/consts.consts.built.after.mir +++ b/tests/mir-opt/building/custom/consts.consts.built.after.mir @@ -10,7 +10,7 @@ fn consts() -> () { bb0: { _1 = const 5_u8; - _2 = const consts::<C>::{constant#1}; + _2 = const consts::<C>::{constant#0}; _3 = const C; _4 = const D; _5 = consts::<10>; diff --git a/tests/mir-opt/building/custom/consts.rs b/tests/mir-opt/building/custom/consts.rs index 1a410177fa5..c64709082dc 100644 --- a/tests/mir-opt/building/custom/consts.rs +++ b/tests/mir-opt/building/custom/consts.rs @@ -9,14 +9,16 @@ const D: i32 = 5; // EMIT_MIR consts.consts.built.after.mir #[custom_mir(dialect = "built")] fn consts<const C: u32>() { - mir!({ - let _a = 5_u8; - let _b = const { 5_i8 }; - let _c = C; - let _d = D; - let _e = consts::<10>; - Return() - }) + mir! { + { + let _a = 5_u8; + let _b = const { 5_i8 }; + let _c = C; + let _d = D; + let _e = consts::<10>; + Return() + } + } } static S: i32 = 0x05050505; @@ -24,11 +26,13 @@ static mut T: i32 = 0x0a0a0a0a; // EMIT_MIR consts.statics.built.after.mir #[custom_mir(dialect = "built")] fn statics() { - mir!({ - let _a: &i32 = Static(S); - let _b: *mut i32 = StaticMut(T); - Return() - }) + mir! { + { + let _a: &i32 = Static(S); + let _b: *mut i32 = StaticMut(T); + Return() + } + } } fn main() { diff --git a/tests/mir-opt/building/custom/debuginfo.rs b/tests/mir-opt/building/custom/debuginfo.rs index 3671a1ef061..5ab83fd4214 100644 --- a/tests/mir-opt/building/custom/debuginfo.rs +++ b/tests/mir-opt/building/custom/debuginfo.rs @@ -7,60 +7,62 @@ use core::intrinsics::mir::*; // EMIT_MIR debuginfo.pointee.built.after.mir #[custom_mir(dialect = "built")] fn pointee(opt: &mut Option<i32>) { - mir!( + mir! { debug foo => Field::<i32>(Variant(*opt, 1), 0); { Return() } - ) + } } // EMIT_MIR debuginfo.numbered.built.after.mir #[custom_mir(dialect = "analysis", phase = "post-cleanup")] fn numbered(i: (u32, i32)) { - mir!( + mir! { debug first => i.0; debug second => i.0; { Return() } - ) + } } -struct S { x: f32 } +struct S { + x: f32, +} // EMIT_MIR debuginfo.structured.built.after.mir #[custom_mir(dialect = "analysis", phase = "post-cleanup")] fn structured(i: S) { - mir!( + mir! { debug x => i.x; { Return() } - ) + } } // EMIT_MIR debuginfo.variant.built.after.mir #[custom_mir(dialect = "built")] fn variant(opt: Option<i32>) { - mir!( + mir! { debug inner => Field::<i32>(Variant(opt, 1), 0); { Return() } - ) + } } // EMIT_MIR debuginfo.variant_deref.built.after.mir #[custom_mir(dialect = "built")] fn variant_deref(opt: Option<&i32>) { - mir!( + mir! { debug pointer => Field::<&i32>(Variant(opt, 1), 0); debug deref => *Field::<&i32>(Variant(opt, 1), 0); { Return() } - ) + } } fn main() { diff --git a/tests/mir-opt/building/custom/enums.rs b/tests/mir-opt/building/custom/enums.rs index 6aab1503c0a..88ec228986a 100644 --- a/tests/mir-opt/building/custom/enums.rs +++ b/tests/mir-opt/building/custom/enums.rs @@ -7,7 +7,7 @@ use core::intrinsics::mir::*; // EMIT_MIR enums.switch_bool.built.after.mir #[custom_mir(dialect = "built")] pub fn switch_bool(b: bool) -> u32 { - mir!( + mir! { { match b { true => t, @@ -25,13 +25,13 @@ pub fn switch_bool(b: bool) -> u32 { RET = 10; Return() } - ) + } } // EMIT_MIR enums.switch_option.built.after.mir #[custom_mir(dialect = "built")] pub fn switch_option(option: Option<()>) -> bool { - mir!( + mir! { { let discr = Discriminant(option); match discr { @@ -50,7 +50,7 @@ pub fn switch_option(option: Option<()>) -> bool { RET = true; Return() } - ) + } } #[repr(u8)] @@ -62,7 +62,7 @@ enum Bool { // EMIT_MIR enums.switch_option_repr.built.after.mir #[custom_mir(dialect = "built")] fn switch_option_repr(option: Bool) -> bool { - mir!( + mir! { { let discr = Discriminant(option); match discr { @@ -80,26 +80,30 @@ fn switch_option_repr(option: Bool) -> bool { RET = false; Return() } - ) + } } // EMIT_MIR enums.set_discr.built.after.mir #[custom_mir(dialect = "runtime", phase = "initial")] fn set_discr(option: &mut Option<()>) { - mir!({ - Deinit(*option); - SetDiscriminant(*option, 0); - Return() - }) + mir! { + { + Deinit(*option); + SetDiscriminant(*option, 0); + Return() + } + } } // EMIT_MIR enums.set_discr_repr.built.after.mir #[custom_mir(dialect = "runtime", phase = "initial")] fn set_discr_repr(b: &mut Bool) { - mir!({ - SetDiscriminant(*b, 0); - Return() - }) + mir! { + { + SetDiscriminant(*b, 0); + Return() + } + } } fn main() { diff --git a/tests/mir-opt/building/custom/operators.rs b/tests/mir-opt/building/custom/operators.rs index ff0e8dcbb41..07abf2d9651 100644 --- a/tests/mir-opt/building/custom/operators.rs +++ b/tests/mir-opt/building/custom/operators.rs @@ -6,37 +6,41 @@ use std::intrinsics::mir::*; // EMIT_MIR operators.f.built.after.mir #[custom_mir(dialect = "built")] pub fn f(a: i32, b: bool) -> i32 { - mir!({ - a = -a; - b = !b; - a = a + a; - a = a - a; - a = a * a; - a = a / a; - a = a % a; - a = a ^ a; - a = a & a; - a = a << a; - a = a >> a; - b = a == a; - b = a < a; - b = a <= a; - b = a >= a; - b = a > a; - let res = Checked(a + a); - b = res.1; - a = res.0; - RET = a; - Return() - }) + mir! { + { + a = -a; + b = !b; + a = a + a; + a = a - a; + a = a * a; + a = a / a; + a = a % a; + a = a ^ a; + a = a & a; + a = a << a; + a = a >> a; + b = a == a; + b = a < a; + b = a <= a; + b = a >= a; + b = a > a; + let res = Checked(a + a); + b = res.1; + a = res.0; + RET = a; + Return() + } + } } // EMIT_MIR operators.g.runtime.after.mir #[custom_mir(dialect = "runtime")] pub fn g(p: *const i32, q: *const [i32]) { - mir!({ - let a = PtrMetadata(p); - let b = PtrMetadata(q); - Return() - }) + mir! { + { + let a = PtrMetadata(p); + let b = PtrMetadata(q); + Return() + } + } } diff --git a/tests/mir-opt/building/custom/projections.rs b/tests/mir-opt/building/custom/projections.rs index ac23fe59097..0250b9b84b6 100644 --- a/tests/mir-opt/building/custom/projections.rs +++ b/tests/mir-opt/building/custom/projections.rs @@ -12,74 +12,84 @@ union U { // EMIT_MIR projections.unions.built.after.mir #[custom_mir(dialect = "built")] fn unions(u: U) -> i32 { - mir!({ - RET = u.a; - Return() - }) + mir! { + { + RET = u.a; + Return() + } + } } // EMIT_MIR projections.tuples.built.after.mir #[custom_mir(dialect = "analysis", phase = "post-cleanup")] fn tuples(i: (u32, i32)) -> (u32, i32) { - mir!( + mir! { type RET = (u32, i32); { RET.0 = i.0; RET.1 = i.1; Return() } - ) + } } // EMIT_MIR projections.unwrap.built.after.mir #[custom_mir(dialect = "built")] fn unwrap(opt: Option<i32>) -> i32 { - mir!({ - RET = Field(Variant(opt, 1), 0); - Return() - }) + mir! { + { + RET = Field(Variant(opt, 1), 0); + Return() + } + } } // EMIT_MIR projections.unwrap_deref.built.after.mir #[custom_mir(dialect = "built")] fn unwrap_deref(opt: Option<&i32>) -> i32 { - mir!({ - RET = *Field::<&i32>(Variant(opt, 1), 0); - Return() - }) + mir! { + { + RET = *Field::<&i32>(Variant(opt, 1), 0); + Return() + } + } } // EMIT_MIR projections.set.built.after.mir #[custom_mir(dialect = "built")] fn set(opt: &mut Option<i32>) { - mir!({ - place!(Field(Variant(*opt, 1), 0)) = 10; - Return() - }) + mir! { + { + place!(Field(Variant(*opt, 1), 0)) = 10; + Return() + } + } } // EMIT_MIR projections.simple_index.built.after.mir #[custom_mir(dialect = "built")] fn simple_index(a: [i32; 10], b: &[i32]) -> i32 { - mir!({ - let temp = 3; - RET = a[temp]; - RET = (*b)[temp]; - Return() - }) + mir! { + { + let temp = 3; + RET = a[temp]; + RET = (*b)[temp]; + Return() + } + } } // EMIT_MIR projections.copy_for_deref.built.after.mir #[custom_mir(dialect = "runtime", phase = "initial")] fn copy_for_deref(x: (&i32, i32)) -> i32 { - mir!( + mir! { let temp: &i32; { temp = CopyForDeref(x.0); RET = *temp; Return() } - ) + } } fn main() { diff --git a/tests/mir-opt/building/custom/references.rs b/tests/mir-opt/building/custom/references.rs index 04afe6e6494..7ea8f8b4c15 100644 --- a/tests/mir-opt/building/custom/references.rs +++ b/tests/mir-opt/building/custom/references.rs @@ -8,31 +8,29 @@ use core::ptr::{addr_of, addr_of_mut}; // EMIT_MIR references.mut_ref.built.after.mir #[custom_mir(dialect = "runtime", phase = "optimized")] pub fn mut_ref(x: &mut i32) -> &mut i32 { - mir!( + mir! { let t: *mut i32; - { t = addr_of_mut!(*x); RET = &mut *t; Retag(RET); Return() } - ) + } } // EMIT_MIR references.immut_ref.built.after.mir #[custom_mir(dialect = "runtime", phase = "optimized")] pub fn immut_ref(x: &i32) -> &i32 { - mir!( + mir! { let t: *const i32; - { t = addr_of!(*x); RET = & *t; Retag(RET); Return() } - ) + } } // EMIT_MIR references.raw_pointer.built.after.mir @@ -40,19 +38,23 @@ pub fn immut_ref(x: &i32) -> &i32 { pub fn raw_pointer(x: *const i32) -> *const i32 { // Regression test for a bug in which unsafetyck was not correctly turned off for // `dialect = "built"` - mir!({ - RET = addr_of!(*x); - Return() - }) + mir! { + { + RET = addr_of!(*x); + Return() + } + } } // EMIT_MIR references.raw_pointer_offset.built.after.mir #[custom_mir(dialect = "built")] pub fn raw_pointer_offset(x: *const i32) -> *const i32 { - mir!({ - RET = Offset(x, 1_isize); - Return() - }) + mir! { + { + RET = Offset(x, 1_isize); + Return() + } + } } fn main() { diff --git a/tests/mir-opt/building/custom/simple_assign.rs b/tests/mir-opt/building/custom/simple_assign.rs index 8442272291e..d6d054ab5a3 100644 --- a/tests/mir-opt/building/custom/simple_assign.rs +++ b/tests/mir-opt/building/custom/simple_assign.rs @@ -7,32 +7,32 @@ use core::intrinsics::mir::*; // EMIT_MIR simple_assign.simple.built.after.mir #[custom_mir(dialect = "built")] pub fn simple(x: i32) -> i32 { - mir!( + mir! { let temp1: i32; let temp2: _; - { StorageLive(temp1); temp1 = x; Goto(exit) } - exit = { temp2 = Move(temp1); StorageDead(temp1); RET = temp2; Return() } - ) + } } // EMIT_MIR simple_assign.simple_ref.built.after.mir #[custom_mir(dialect = "built")] pub fn simple_ref(x: &mut i32) -> &mut i32 { - mir!({ - RET = Move(x); - Return() - }) + mir! { + { + RET = Move(x); + Return() + } + } } fn main() { diff --git a/tests/mir-opt/building/custom/terminators.rs b/tests/mir-opt/building/custom/terminators.rs index 01c132cf3e7..a8e0b4b35bf 100644 --- a/tests/mir-opt/building/custom/terminators.rs +++ b/tests/mir-opt/building/custom/terminators.rs @@ -11,7 +11,7 @@ fn ident<T>(t: T) -> T { // EMIT_MIR terminators.direct_call.built.after.mir #[custom_mir(dialect = "built")] fn direct_call(x: i32) -> i32 { - mir!( + mir! { { Call(RET = ident(x), ReturnTo(retblock), UnwindContinue()) } @@ -19,21 +19,20 @@ fn direct_call(x: i32) -> i32 { retblock = { Return() } - ) + } } // EMIT_MIR terminators.indirect_call.built.after.mir #[custom_mir(dialect = "built")] fn indirect_call(x: i32, f: fn(i32) -> i32) -> i32 { - mir!( + mir! { { Call(RET = f(x), ReturnTo(retblock), UnwindContinue()) } - retblock = { Return() } - ) + } } struct WriteOnDrop<'a>(&'a mut i32, i32); @@ -47,51 +46,47 @@ impl<'a> Drop for WriteOnDrop<'a> { // EMIT_MIR terminators.drop_first.built.after.mir #[custom_mir(dialect = "built")] fn drop_first<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) { - mir!( + mir! { { Drop(a, ReturnTo(retblock), UnwindContinue()) } - retblock = { a = Move(b); Return() } - ) + } } // EMIT_MIR terminators.drop_second.built.after.mir #[custom_mir(dialect = "built")] fn drop_second<'a>(a: WriteOnDrop<'a>, b: WriteOnDrop<'a>) { - mir!( + mir! { { Drop(b, ReturnTo(retblock), UnwindContinue()) } - retblock = { Return() } - ) + } } // EMIT_MIR terminators.assert_nonzero.built.after.mir #[custom_mir(dialect = "built")] fn assert_nonzero(a: i32) { - mir!( + mir! { { match a { 0 => unreachable, _ => retblock } } - unreachable = { Unreachable() } - retblock = { Return() } - ) + } } fn main() { diff --git a/tests/mir-opt/building/custom/unwind_action.rs b/tests/mir-opt/building/custom/unwind_action.rs index e3d54c72145..87aab1ea70c 100644 --- a/tests/mir-opt/building/custom/unwind_action.rs +++ b/tests/mir-opt/building/custom/unwind_action.rs @@ -9,14 +9,14 @@ use core::intrinsics::mir::*; // CHECK-NEXT: a() -> [return: bb1, unwind unreachable]; #[custom_mir(dialect = "runtime", phase = "optimized")] pub fn a() { - mir!( + mir! { { Call(RET = a(), ReturnTo(bb1), UnwindUnreachable()) } bb1 = { Return() } - ) + } } // CHECK-LABEL: fn b() @@ -24,14 +24,14 @@ pub fn a() { // CHECK-NEXT: b() -> [return: bb1, unwind continue]; #[custom_mir(dialect = "runtime", phase = "optimized")] pub fn b() { - mir!( + mir! { { Call(RET = b(), ReturnTo(bb1), UnwindContinue()) } bb1 = { Return() } - ) + } } // CHECK-LABEL: fn c() @@ -39,14 +39,14 @@ pub fn b() { // CHECK-NEXT: c() -> [return: bb1, unwind terminate(abi)]; #[custom_mir(dialect = "runtime", phase = "optimized")] pub fn c() { - mir!( + mir! { { Call(RET = c(), ReturnTo(bb1), UnwindTerminate(ReasonAbi)) } bb1 = { Return() } - ) + } } // CHECK-LABEL: fn d() @@ -54,7 +54,7 @@ pub fn c() { // CHECK-NEXT: d() -> [return: bb1, unwind: bb2]; #[custom_mir(dialect = "runtime", phase = "optimized")] pub fn d() { - mir!( + mir! { { Call(RET = d(), ReturnTo(bb1), UnwindCleanup(bb2)) } @@ -64,5 +64,5 @@ pub fn d() { bb2 (cleanup) = { UnwindResume() } - ) + } } diff --git a/tests/mir-opt/building/custom/unwind_terminate.rs b/tests/mir-opt/building/custom/unwind_terminate.rs index c5374fa7b69..9b495d52387 100644 --- a/tests/mir-opt/building/custom/unwind_terminate.rs +++ b/tests/mir-opt/building/custom/unwind_terminate.rs @@ -8,14 +8,14 @@ use core::intrinsics::mir::*; // CHECK-NEXT: terminate(abi); #[custom_mir(dialect = "runtime", phase = "optimized")] pub fn f() { - mir!( + mir! { { Return() } bb1(cleanup) = { UnwindTerminate(ReasonAbi) } - ) + } } // CHECK-LABEL: fn g() @@ -23,12 +23,12 @@ pub fn f() { // CHECK-NEXT: terminate(cleanup); #[custom_mir(dialect = "runtime", phase = "optimized")] pub fn g() { - mir!( + mir! { { Return() } bb1(cleanup) = { UnwindTerminate(ReasonInCleanup) } - ) + } } diff --git a/tests/mir-opt/building/enum_cast.rs b/tests/mir-opt/building/enum_cast.rs index df8e397c8fe..7ff0cdbfe8d 100644 --- a/tests/mir-opt/building/enum_cast.rs +++ b/tests/mir-opt/building/enum_cast.rs @@ -5,21 +5,24 @@ // EMIT_MIR enum_cast.far.built.after.mir enum Foo { - A + A, } enum Bar { - A, B + A, + B, } #[repr(u8)] enum Boo { - A, B + A, + B, } #[repr(i16)] enum Far { - A, B + A, + B, } fn foo(foo: Foo) -> usize { @@ -40,7 +43,9 @@ fn far(far: Far) -> isize { // EMIT_MIR enum_cast.droppy.built.after.mir enum Droppy { - A, B, C + A, + B, + C, } impl Drop for Droppy { @@ -82,12 +87,15 @@ fn unsigny(x: UnsignedAroundZero) -> u16 { x as u16 } -enum NotStartingAtZero { A = 4, B = 6, C = 8 } +enum NotStartingAtZero { + A = 4, + B = 6, + C = 8, +} // EMIT_MIR enum_cast.offsetty.built.after.mir fn offsetty(x: NotStartingAtZero) -> u32 { x as u32 } -fn main() { -} +fn main() {} diff --git a/tests/mir-opt/building/logical_or_in_conditional.rs b/tests/mir-opt/building/logical_or_in_conditional.rs index deb841f2b0d..e6872e6f2ec 100644 --- a/tests/mir-opt/building/logical_or_in_conditional.rs +++ b/tests/mir-opt/building/logical_or_in_conditional.rs @@ -30,9 +30,13 @@ fn test_or() { // EMIT_MIR logical_or_in_conditional.test_complex.built.after.mir fn test_complex() { - if let E::A(_) = E::f() && ((always_true() && Droppy(0).0 > 0) || Droppy(1).0 > 1) {} + if let E::A(_) = E::f() + && ((always_true() && Droppy(0).0 > 0) || Droppy(1).0 > 1) + {} - if !always_true() && let E::B = E::f() {} + if !always_true() + && let E::B = E::f() + {} } fn main() { diff --git a/tests/mir-opt/building/match/simple_match.rs b/tests/mir-opt/building/match/simple_match.rs index 4f0a3046a06..61c337822c8 100644 --- a/tests/mir-opt/building/match/simple_match.rs +++ b/tests/mir-opt/building/match/simple_match.rs @@ -1,7 +1,6 @@ // skip-filecheck // Test that we don't generate unnecessarily large MIR for very simple matches - // EMIT_MIR simple_match.match_bool.built.after.mir fn match_bool(x: bool) -> usize { match x { diff --git a/tests/mir-opt/building/match/sort_candidates.rs b/tests/mir-opt/building/match/sort_candidates.rs index f207f0b3234..593a975a7a4 100644 --- a/tests/mir-opt/building/match/sort_candidates.rs +++ b/tests/mir-opt/building/match/sort_candidates.rs @@ -5,9 +5,9 @@ fn constant_eq(s: &str, b: bool) -> u32 { // Check that we only test "a" once // CHECK-LABEL: fn constant_eq( - // CHECK: bb0: { - // CHECK: [[a:_.*]] = const "a"; - // CHECK-NOT: {{_.*}} = const "a"; + // CHECK-NOT: const "a" + // CHECK: {{_[0-9]+}} = const "a" as &[u8] (Transmute); + // CHECK-NOT: const "a" match (s, b) { ("a", _) if true => 1, ("b", true) => 2, diff --git a/tests/mir-opt/building/shifts.rs b/tests/mir-opt/building/shifts.rs index 849d7b55f3a..d7747bb2f78 100644 --- a/tests/mir-opt/building/shifts.rs +++ b/tests/mir-opt/building/shifts.rs @@ -3,19 +3,12 @@ // EMIT_MIR shifts.shift_signed.built.after.mir fn shift_signed(small: i8, big: u128, a: i8, b: i32, c: i128) -> ([i8; 3], [u128; 3]) { - ( - [small >> a, small >> b, small >> c], - [big << a, big << b, big << c], - ) + ([small >> a, small >> b, small >> c], [big << a, big << b, big << c]) } // EMIT_MIR shifts.shift_unsigned.built.after.mir fn shift_unsigned(small: u8, big: i128, a: u8, b: u32, c: u128) -> ([u8; 3], [i128; 3]) { - ( - [small >> a, small >> b, small >> c], - [big << a, big << b, big << c], - ) + ([small >> a, small >> b, small >> c], [big << a, big << b, big << c]) } -fn main() { -} +fn main() {} diff --git a/tests/mir-opt/building/storage_live_dead_in_statics.rs b/tests/mir-opt/building/storage_live_dead_in_statics.rs index 1f569211854..7cb74acbf06 100644 --- a/tests/mir-opt/building/storage_live_dead_in_statics.rs +++ b/tests/mir-opt/building/storage_live_dead_in_statics.rs @@ -3,6 +3,7 @@ // generate `StorageStart` or `StorageEnd` statements. // EMIT_MIR storage_live_dead_in_statics.XXX.built.after.mir +#[rustfmt::skip] static XXX: &'static Foo = &Foo { tup: "hi", data: &[ @@ -20,13 +21,13 @@ static XXX: &'static Foo = &Foo { (0, 1), (0, 2), (0, 3), (0, 1), (0, 2), (0, 3), (0, 1), (0, 2), (0, 3), - ] + ], }; #[derive(Debug)] struct Foo { tup: &'static str, - data: &'static [(u32, u32)] + data: &'static [(u32, u32)], } fn main() { diff --git a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff b/tests/mir-opt/const_debuginfo.main.SingleUseConsts.diff index c1529dbee13..ac33f51984c 100644 --- a/tests/mir-opt/const_debuginfo.main.ConstDebugInfo.diff +++ b/tests/mir-opt/const_debuginfo.main.SingleUseConsts.diff @@ -1,5 +1,5 @@ -- // MIR for `main` before ConstDebugInfo -+ // MIR for `main` after ConstDebugInfo +- // MIR for `main` before SingleUseConsts ++ // MIR for `main` after SingleUseConsts fn main() -> () { let mut _0: (); @@ -56,39 +56,53 @@ bb0: { nop; - _1 = const 1_u8; +- _1 = const 1_u8; nop; - _2 = const 2_u8; +- _2 = const 2_u8; nop; - _3 = const 3_u8; +- _3 = const 3_u8; ++ nop; ++ nop; ++ nop; StorageLive(_4); StorageLive(_5); StorageLive(_6); - _6 = const 1_u8; +- _6 = const 1_u8; ++ nop; StorageLive(_7); - _7 = const 2_u8; - _5 = const 3_u8; +- _7 = const 2_u8; +- _5 = const 3_u8; ++ nop; ++ nop; StorageDead(_7); StorageDead(_6); StorageLive(_8); - _8 = const 3_u8; - _4 = const 6_u8; +- _8 = const 3_u8; +- _4 = const 6_u8; ++ nop; ++ nop; StorageDead(_8); StorageDead(_5); StorageLive(_9); - _9 = const "hello, world!"; +- _9 = const "hello, world!"; ++ nop; StorageLive(_10); _10 = (const true, const false, const 123_u32); StorageLive(_11); - _11 = const Option::<u16>::Some(99_u16); +- _11 = const Option::<u16>::Some(99_u16); ++ nop; StorageLive(_12); - _12 = const Point {{ x: 32_u32, y: 32_u32 }}; +- _12 = const Point {{ x: 32_u32, y: 32_u32 }}; ++ nop; StorageLive(_13); nop; - _14 = const 32_u32; +- _14 = const 32_u32; ++ nop; StorageLive(_15); - _15 = const 32_u32; - _13 = const 64_u32; +- _15 = const 32_u32; +- _13 = const 64_u32; ++ nop; ++ nop; StorageDead(_15); nop; _0 = const (); diff --git a/tests/mir-opt/const_debuginfo.rs b/tests/mir-opt/const_debuginfo.rs index b880d7e07a6..907d7fef067 100644 --- a/tests/mir-opt/const_debuginfo.rs +++ b/tests/mir-opt/const_debuginfo.rs @@ -1,12 +1,14 @@ -//@ test-mir-pass: ConstDebugInfo +//@ test-mir-pass: SingleUseConsts //@ compile-flags: -C overflow-checks=no -Zmir-enable-passes=+GVN +#![allow(unused)] + struct Point { x: u32, y: u32, } -// EMIT_MIR const_debuginfo.main.ConstDebugInfo.diff +// EMIT_MIR const_debuginfo.main.SingleUseConsts.diff fn main() { // CHECK-LABEL: fn main( // CHECK: debug x => const 1_u8; diff --git a/tests/mir-opt/const_prop/control_flow_simplification.rs b/tests/mir-opt/const_prop/control_flow_simplification.rs index 39b5f289830..64605ca11c2 100644 --- a/tests/mir-opt/const_prop/control_flow_simplification.rs +++ b/tests/mir-opt/const_prop/control_flow_simplification.rs @@ -11,7 +11,7 @@ impl<This> NeedsDrop for This {} // EMIT_MIR control_flow_simplification.hello.GVN.diff // EMIT_MIR control_flow_simplification.hello.PreCodegen.before.mir -fn hello<T>(){ +fn hello<T>() { if <bool>::NEEDS { panic!() } diff --git a/tests/mir-opt/const_prop/invalid_constant.rs b/tests/mir-opt/const_prop/invalid_constant.rs index 2b7271f63ff..91ee36ae2c5 100644 --- a/tests/mir-opt/const_prop/invalid_constant.rs +++ b/tests/mir-opt/const_prop/invalid_constant.rs @@ -8,7 +8,11 @@ #[derive(Copy, Clone)] #[repr(u32)] -enum E { A, B, C } +enum E { + A, + B, + C, +} #[derive(Copy, Clone)] enum Empty {} @@ -39,7 +43,5 @@ fn main() { // A non-UTF-8 string slice. Regression test for #75763 and #78520. struct Str<const S: &'static str>; - let _non_utf8_str: Str::<{ - unsafe { std::mem::transmute::<&[u8], &str>(&[0xC0, 0xC1, 0xF5]) } - }>; + let _non_utf8_str: Str<{ unsafe { std::mem::transmute::<&[u8], &str>(&[0xC0, 0xC1, 0xF5]) } }>; } diff --git a/tests/mir-opt/const_prop/offset_of.rs b/tests/mir-opt/const_prop/offset_of.rs index 105cbfb53dd..264c8a3d21c 100644 --- a/tests/mir-opt/const_prop/offset_of.rs +++ b/tests/mir-opt/const_prop/offset_of.rs @@ -31,7 +31,7 @@ struct Delta<T> { enum Epsilon { A(u8, u16), B, - C { c: u32 } + C { c: u32 }, } enum Zeta<T> { diff --git a/tests/mir-opt/const_prop/pointer_expose_provenance.rs b/tests/mir-opt/const_prop/pointer_expose_provenance.rs index f148a5b6542..a76fead9859 100644 --- a/tests/mir-opt/const_prop/pointer_expose_provenance.rs +++ b/tests/mir-opt/const_prop/pointer_expose_provenance.rs @@ -2,7 +2,7 @@ //@ test-mir-pass: GVN #[inline(never)] -fn read(_: usize) { } +fn read(_: usize) {} // EMIT_MIR pointer_expose_provenance.main.GVN.diff fn main() { diff --git a/tests/mir-opt/const_prop/scalar_literal_propagation.rs b/tests/mir-opt/const_prop/scalar_literal_propagation.rs index 9d02f24e76b..15e32490de4 100644 --- a/tests/mir-opt/const_prop/scalar_literal_propagation.rs +++ b/tests/mir-opt/const_prop/scalar_literal_propagation.rs @@ -10,4 +10,4 @@ fn main() { } #[inline(never)] -fn consume(_: u32) { } +fn consume(_: u32) {} diff --git a/tests/mir-opt/const_prop/switch_int.rs b/tests/mir-opt/const_prop/switch_int.rs index 114380e316d..4ee4182caf6 100644 --- a/tests/mir-opt/const_prop/switch_int.rs +++ b/tests/mir-opt/const_prop/switch_int.rs @@ -3,7 +3,7 @@ // EMIT_MIR_FOR_EACH_PANIC_STRATEGY #[inline(never)] -fn foo(_: i32) { } +fn foo(_: i32) {} // EMIT_MIR switch_int.main.GVN.diff // EMIT_MIR switch_int.main.SimplifyConstCondition-after-const-prop.diff diff --git a/tests/mir-opt/const_prop/transmute.rs b/tests/mir-opt/const_prop/transmute.rs index 9cbf8928753..892b91a5414 100644 --- a/tests/mir-opt/const_prop/transmute.rs +++ b/tests/mir-opt/const_prop/transmute.rs @@ -45,7 +45,10 @@ pub unsafe fn undef_union_as_integer() -> u32 { // CHECK-LABEL: fn undef_union_as_integer( // CHECK: _1 = Union32 { // CHECK: _0 = move _1 as u32 (Transmute); - union Union32 { value: u32, unit: () } + union Union32 { + value: u32, + unit: (), + } unsafe { transmute(Union32 { unit: () }) } } diff --git a/tests/mir-opt/const_prop/tuple_literal_propagation.rs b/tests/mir-opt/const_prop/tuple_literal_propagation.rs index 582411c7b59..e42a62cb6fd 100644 --- a/tests/mir-opt/const_prop/tuple_literal_propagation.rs +++ b/tests/mir-opt/const_prop/tuple_literal_propagation.rs @@ -10,4 +10,4 @@ fn main() { } #[inline(never)] -fn consume(_: (u32, u32)) { } +fn consume(_: (u32, u32)) {} diff --git a/tests/mir-opt/copy-prop/borrowed_local.rs b/tests/mir-opt/copy-prop/borrowed_local.rs index 512287dd176..dd1679513f6 100644 --- a/tests/mir-opt/copy-prop/borrowed_local.rs +++ b/tests/mir-opt/copy-prop/borrowed_local.rs @@ -4,10 +4,12 @@ #![feature(custom_mir, core_intrinsics, freeze)] #![allow(unused_assignments)] extern crate core; -use core::marker::Freeze; use core::intrinsics::mir::*; +use core::marker::Freeze; -fn opaque(_: impl Sized) -> bool { true } +fn opaque(_: impl Sized) -> bool { + true +} fn cmp_ref(a: &u8, b: &u8) -> bool { std::ptr::eq(a as *const u8, b as *const u8) @@ -24,7 +26,7 @@ fn compare_address() -> bool { // CHECK-NEXT: _0 = cmp_ref(_2, _4) // CHECK: bb1: { // CHECK-NEXT: _0 = opaque::<u8>(_3) - mir!( + mir! { { let a = 5_u8; let r1 = &a; @@ -40,7 +42,7 @@ fn compare_address() -> bool { ret = { Return() } - ) + } } /// Generic type `T` is `Freeze`, so shared borrows are immutable. @@ -52,7 +54,7 @@ fn borrowed<T: Copy + Freeze>(x: T) -> bool { // CHECK-NEXT: _0 = opaque::<&T>(_3) // CHECK: bb1: { // CHECK-NEXT: _0 = opaque::<T>(_1) - mir!( + mir! { { let a = x; let r1 = &x; @@ -64,7 +66,7 @@ fn borrowed<T: Copy + Freeze>(x: T) -> bool { ret = { Return() } - ) + } } /// Generic type `T` is not known to be `Freeze`, so shared borrows may be mutable. @@ -77,7 +79,7 @@ fn non_freeze<T: Copy>(x: T) -> bool { // CHECK-NEXT: _0 = opaque::<&T>(_3) // CHECK: bb1: { // CHECK-NEXT: _0 = opaque::<T>(_2) - mir!( + mir! { { let a = x; let r1 = &x; @@ -89,7 +91,7 @@ fn non_freeze<T: Copy>(x: T) -> bool { ret = { Return() } - ) + } } fn main() { diff --git a/tests/mir-opt/copy-prop/custom_move_arg.rs b/tests/mir-opt/copy-prop/custom_move_arg.rs index a82d4618e68..3dce7807b34 100644 --- a/tests/mir-opt/copy-prop/custom_move_arg.rs +++ b/tests/mir-opt/copy-prop/custom_move_arg.rs @@ -12,17 +12,19 @@ struct NotCopy(bool); // EMIT_MIR custom_move_arg.f.CopyProp.diff #[custom_mir(dialect = "runtime")] fn f(_1: NotCopy) { - mir!({ - let _2 = _1; - Call(RET = opaque(Move(_1)), ReturnTo(bb1), UnwindUnreachable()) + mir! { + { + let _2 = _1; + Call(RET = opaque(Move(_1)), ReturnTo(bb1), UnwindUnreachable()) + } + bb1 = { + let _3 = Move(_2); + Call(RET = opaque(_3), ReturnTo(bb2), UnwindUnreachable()) + } + bb2 = { + Return() + } } - bb1 = { - let _3 = Move(_2); - Call(RET = opaque(_3), ReturnTo(bb2), UnwindUnreachable()) - } - bb2 = { - Return() - }) } #[inline(never)] diff --git a/tests/mir-opt/copy-prop/move_projection.rs b/tests/mir-opt/copy-prop/move_projection.rs index 231e4082e33..0ac1c4e0ba2 100644 --- a/tests/mir-opt/copy-prop/move_projection.rs +++ b/tests/mir-opt/copy-prop/move_projection.rs @@ -7,13 +7,15 @@ extern crate core; use core::intrinsics::mir::*; -fn opaque(_: impl Sized) -> bool { true } +fn opaque(_: impl Sized) -> bool { + true +} struct Foo(u8); #[custom_mir(dialect = "runtime")] fn f(a: Foo) -> bool { - mir!( + mir! { { let b = a; // This is a move out of a copy, so must become a copy of `a.0`. @@ -26,7 +28,7 @@ fn f(a: Foo) -> bool { ret = { Return() } - ) + } } fn main() { diff --git a/tests/mir-opt/copy-prop/mutate_through_pointer.rs b/tests/mir-opt/copy-prop/mutate_through_pointer.rs index 14ca513c692..53cca045248 100644 --- a/tests/mir-opt/copy-prop/mutate_through_pointer.rs +++ b/tests/mir-opt/copy-prop/mutate_through_pointer.rs @@ -18,14 +18,16 @@ use core::intrinsics::mir::*; #[custom_mir(dialect = "analysis", phase = "post-cleanup")] fn f(c: bool) -> bool { - mir!({ - let a = c; - let p = core::ptr::addr_of!(a); - let p2 = core::ptr::addr_of_mut!(*p); - *p2 = false; - RET = c; - Return() - }) + mir! { + { + let a = c; + let p = core::ptr::addr_of!(a); + let p2 = core::ptr::addr_of_mut!(*p); + *p2 = false; + RET = c; + Return() + } + } } fn main() { diff --git a/tests/mir-opt/copy-prop/non_dominate.rs b/tests/mir-opt/copy-prop/non_dominate.rs index 34e7eabc81a..c01275370ea 100644 --- a/tests/mir-opt/copy-prop/non_dominate.rs +++ b/tests/mir-opt/copy-prop/non_dominate.rs @@ -8,16 +8,28 @@ use core::intrinsics::mir::*; #[custom_mir(dialect = "analysis", phase = "post-cleanup")] fn f(c: bool) -> bool { - mir!( + mir! { let a: bool; let b: bool; - { Goto(bb1) } - bb1 = { b = c; match b { false => bb3, _ => bb2 }} + { + Goto(bb1) + } + bb1 = { + b = c; + match b { false => bb3, _ => bb2 } + } // This assignment to `a` does not dominate the use in `bb3`. // It should not be replaced by `b`. - bb2 = { a = b; c = false; Goto(bb1) } - bb3 = { RET = a; Return() } - ) + bb2 = { + a = b; + c = false; + Goto(bb1) + } + bb3 = { + RET = a; + Return() + } + } } fn main() { diff --git a/tests/mir-opt/dataflow-const-prop/enum.rs b/tests/mir-opt/dataflow-const-prop/enum.rs index 5c52f92cd8f..946cfa4c76c 100644 --- a/tests/mir-opt/dataflow-const-prop/enum.rs +++ b/tests/mir-opt/dataflow-const-prop/enum.rs @@ -8,7 +8,7 @@ use std::intrinsics::mir::*; #[derive(Copy, Clone)] enum E { V1(i32), - V2(i32) + V2(i32), } // EMIT_MIR enum.simple.DataflowConstProp.diff @@ -23,7 +23,10 @@ fn simple() { // CHECK: switchInt(const 0_isize) -> [0: [[target_bb:bb.*]], 1: bb2, otherwise: bb1]; // CHECK: [[target_bb]]: { // CHECK: [[x]] = const 0_i32; - let x = match e { E::V1(x1) => x1, E::V2(x2) => x2 }; + let x = match e { + E::V1(x1) => x1, + E::V2(x2) => x2, + }; } // EMIT_MIR enum.constant.DataflowConstProp.diff @@ -39,7 +42,10 @@ fn constant() { // CHECK: switchInt(const 0_isize) -> [0: [[target_bb:bb.*]], 1: bb2, otherwise: bb1]; // CHECK: [[target_bb]]: { // CHECK: [[x]] = const 0_i32; - let x = match e { E::V1(x1) => x1, E::V2(x2) => x2 }; + let x = match e { + E::V1(x1) => x1, + E::V2(x2) => x2, + }; } // EMIT_MIR enum.statics.DataflowConstProp.diff @@ -58,7 +64,10 @@ fn statics() { // CHECK: switchInt(const 0_isize) -> [0: [[target_bb:bb.*]], 1: bb2, otherwise: bb1]; // CHECK: [[target_bb]]: { // CHECK: [[x1]] = const 0_i32; - let x1 = match e1 { E::V1(x11) => x11, E::V2(x12) => x12 }; + let x1 = match e1 { + E::V1(x11) => x11, + E::V2(x12) => x12, + }; static RC: &E = &E::V2(4); @@ -72,7 +81,10 @@ fn statics() { // One is `_9 = &(*_12) and another is `_9 = _11`. It is different from what we can // get by printing MIR directly. It is better to check if there are any bugs in the // MIR passes around this stage. - let x2 = match e2 { E::V1(x21) => x21, E::V2(x22) => x22 }; + let x2 = match e2 { + E::V1(x21) => x21, + E::V2(x22) => x22, + }; } #[rustc_layout_scalar_valid_range_start(1)] @@ -84,7 +96,7 @@ struct NonZeroUsize(usize); // CHECK-LABEL: fn mutate_discriminant( #[custom_mir(dialect = "runtime", phase = "post-cleanup")] fn mutate_discriminant() -> u8 { - mir!( + mir! { let x: Option<NonZeroUsize>; { SetDiscriminant(x, 1); @@ -109,7 +121,7 @@ fn mutate_discriminant() -> u8 { RET = 2; Unreachable() } - ) + } } // EMIT_MIR enum.multiple.DataflowConstProp.diff @@ -132,7 +144,10 @@ fn multiple(x: bool, i: u8) { // CHECK: [[x2]] = const 0_u8; // CHECK: [[some:_.*]] = (({{_.*}} as Some).0: u8) // CHECK: [[x2]] = [[some]]; - let x2 = match e { Some(i) => i, None => 0 }; + let x2 = match e { + Some(i) => i, + None => 0, + }; // Therefore, `x2` should be `Top` here, and no replacement shall happen. diff --git a/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs b/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs index 3cd0b715a52..26f79c8c0e4 100644 --- a/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs +++ b/tests/mir-opt/dataflow-const-prop/mult_by_zero.rs @@ -2,9 +2,9 @@ // EMIT_MIR mult_by_zero.test.DataflowConstProp.diff // CHECK-LABEL: fn test( -fn test(x : i32) -> i32 { - x * 0 - // CHECK: _0 = const 0_i32; +fn test(x: i32) -> i32 { + x * 0 + // CHECK: _0 = const 0_i32; } fn main() { diff --git a/tests/mir-opt/dataflow-const-prop/transmute.rs b/tests/mir-opt/dataflow-const-prop/transmute.rs index e7f93f421cf..d0391f6974b 100644 --- a/tests/mir-opt/dataflow-const-prop/transmute.rs +++ b/tests/mir-opt/dataflow-const-prop/transmute.rs @@ -45,7 +45,10 @@ pub unsafe fn undef_union_as_integer() -> u32 { // CHECK-LABEL: fn undef_union_as_integer( // CHECK: _1 = Union32 { // CHECK: _0 = move _1 as u32 (Transmute); - union Union32 { value: u32, unit: () } + union Union32 { + value: u32, + unit: (), + } unsafe { transmute(Union32 { unit: () }) } } diff --git a/tests/mir-opt/dead-store-elimination/call_arg_copy.rs b/tests/mir-opt/dead-store-elimination/call_arg_copy.rs index edb35061cc6..2556848ec46 100644 --- a/tests/mir-opt/dead-store-elimination/call_arg_copy.rs +++ b/tests/mir-opt/dead-store-elimination/call_arg_copy.rs @@ -29,7 +29,7 @@ struct Packed { fn move_packed(packed: Packed) { // CHECK-LABEL: fn move_packed( // CHECK: = use_both(const 0_i32, (_1.1: i32)) - mir!( + mir! { { // We have a packed struct, verify that the copy is not turned into a move. Call(RET = use_both(0, packed.y), ReturnTo(ret), UnwindContinue()) @@ -37,7 +37,7 @@ fn move_packed(packed: Packed) { ret = { Return() } - ) + } } fn main() { diff --git a/tests/mir-opt/dead-store-elimination/cycle.rs b/tests/mir-opt/dead-store-elimination/cycle.rs index 795d57d36f5..c8f0c2644ab 100644 --- a/tests/mir-opt/dead-store-elimination/cycle.rs +++ b/tests/mir-opt/dead-store-elimination/cycle.rs @@ -20,7 +20,7 @@ fn cycle(mut x: i32, mut y: i32, mut z: i32) { // CHECK-NOT: {{_.*}} = move {{_.*}}; // We use custom MIR to avoid generating debuginfo, that would force to preserve writes. - mir!( + mir! { let condition: bool; { Call(condition = cond(), ReturnTo(bb1), UnwindContinue()) @@ -38,7 +38,7 @@ fn cycle(mut x: i32, mut y: i32, mut z: i32) { ret = { Return() } - ) + } } fn main() { diff --git a/tests/mir-opt/derefer_complex_case.rs b/tests/mir-opt/derefer_complex_case.rs index b1fa2c8733e..96034522b9f 100644 --- a/tests/mir-opt/derefer_complex_case.rs +++ b/tests/mir-opt/derefer_complex_case.rs @@ -4,5 +4,7 @@ // EMIT_MIR_FOR_EACH_PANIC_STRATEGY fn main() { - for &foo in &[42, 43] { drop(foo) } + for &foo in &[42, 43] { + drop(foo) + } } diff --git a/tests/mir-opt/derefer_terminator_test.rs b/tests/mir-opt/derefer_terminator_test.rs index 5de6a61eaf2..fd16c6c2045 100644 --- a/tests/mir-opt/derefer_terminator_test.rs +++ b/tests/mir-opt/derefer_terminator_test.rs @@ -7,7 +7,9 @@ fn main() { let b = foo(); let d = foo(); match ****(&&&&b) { - true => {let x = 5;}, + true => { + let x = 5; + } false => {} } let y = 42; diff --git a/tests/mir-opt/derefer_test.rs b/tests/mir-opt/derefer_test.rs index 3ca2144e4fc..5676fa657fe 100644 --- a/tests/mir-opt/derefer_test.rs +++ b/tests/mir-opt/derefer_test.rs @@ -2,7 +2,7 @@ //@ test-mir-pass: Derefer // EMIT_MIR derefer_test.main.Derefer.diff fn main() { - let mut a = (42,43); + let mut a = (42, 43); let mut b = (99, &mut a); let x = &mut (*b.1).0; let y = &mut (*b.1).1; diff --git a/tests/mir-opt/derefer_test_multiple.rs b/tests/mir-opt/derefer_test_multiple.rs index 145a19ee6a3..7c03af00e1e 100644 --- a/tests/mir-opt/derefer_test_multiple.rs +++ b/tests/mir-opt/derefer_test_multiple.rs @@ -1,7 +1,7 @@ // skip-filecheck //@ test-mir-pass: Derefer // EMIT_MIR derefer_test_multiple.main.Derefer.diff -fn main () { +fn main() { let mut a = (42, 43); let mut b = (99, &mut a); let mut c = (11, &mut b); diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff index 570ec129f06..b596e25ddfd 100644 --- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff +++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff @@ -18,7 +18,7 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = const 1_u32; + nop; _1 = Un { us: const 1_u32 }; StorageDead(_2); StorageLive(_3); diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff index 570ec129f06..b596e25ddfd 100644 --- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff +++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff @@ -18,7 +18,7 @@ bb0: { StorageLive(_1); StorageLive(_2); - _2 = const 1_u32; + nop; _1 = Un { us: const 1_u32 }; StorageDead(_2); StorageLive(_3); diff --git a/tests/mir-opt/enum_opt.rs b/tests/mir-opt/enum_opt.rs index cacc7301f12..2cc5df84d6b 100644 --- a/tests/mir-opt/enum_opt.rs +++ b/tests/mir-opt/enum_opt.rs @@ -7,22 +7,22 @@ // Tests that an enum with a variant with no data gets correctly transformed. pub enum NoData { - Large([u8; 8196]), - None, + Large([u8; 8196]), + None, } // Tests that an enum with a variant with data that is a valid candidate gets transformed. pub enum Candidate { - Small(u8), - Large([u8; 8196]), + Small(u8), + Large([u8; 8196]), } // Tests that an enum which has a discriminant much higher than the variant does not get // tformed. #[repr(u32)] pub enum InvalidIdxs { - A = 302, - Large([u64; 1024]), + A = 302, + Large([u64; 1024]), } // Tests that an enum with too high of a discriminant index (not in bounds of usize) does not @@ -37,51 +37,51 @@ pub enum NotTrunctable { // Tests that an enum with discriminants in random order still gets tformed correctly. #[repr(u32)] pub enum RandOrderDiscr { - A = 13, - B([u8; 1024]) = 5, - C = 7, + A = 13, + B([u8; 1024]) = 5, + C = 7, } // EMIT_MIR enum_opt.unin.EnumSizeOpt.diff pub fn unin() -> NoData { - let mut a = NoData::None; - a = NoData::Large([1; 8196]); - a + let mut a = NoData::None; + a = NoData::Large([1; 8196]); + a } // EMIT_MIR enum_opt.cand.EnumSizeOpt.diff pub fn cand() -> Candidate { - let mut a = Candidate::Small(1); - a = Candidate::Large([1; 8196]); - a + let mut a = Candidate::Small(1); + a = Candidate::Large([1; 8196]); + a } // EMIT_MIR enum_opt.invalid.EnumSizeOpt.diff pub fn invalid() -> InvalidIdxs { - let mut a = InvalidIdxs::A; - a = InvalidIdxs::Large([0; 1024]); - a + let mut a = InvalidIdxs::A; + a = InvalidIdxs::Large([0; 1024]); + a } // EMIT_MIR enum_opt.trunc.EnumSizeOpt.diff pub fn trunc() -> NotTrunctable { - let mut a = NotTrunctable::A; - a = NotTrunctable::B([0; 1024]); - a = NotTrunctable::C([0; 4096]); - a + let mut a = NotTrunctable::A; + a = NotTrunctable::B([0; 1024]); + a = NotTrunctable::C([0; 4096]); + a } pub fn rand_order() -> RandOrderDiscr { - let mut a = RandOrderDiscr::A; - a = RandOrderDiscr::B([0; 1024]); - a = RandOrderDiscr::C; - a + let mut a = RandOrderDiscr::A; + a = RandOrderDiscr::B([0; 1024]); + a = RandOrderDiscr::C; + a } pub fn main() { - unin(); - cand(); - invalid(); - trunc(); - rand_order(); + unin(); + cand(); + invalid(); + trunc(); + rand_order(); } diff --git a/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-abort.diff b/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-abort.diff new file mode 100644 index 00000000000..6e5bdb16595 --- /dev/null +++ b/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-abort.diff @@ -0,0 +1,60 @@ +- // MIR for `casts_before_aggregate_raw_ptr` before GVN ++ // MIR for `casts_before_aggregate_raw_ptr` after GVN + + fn casts_before_aggregate_raw_ptr(_1: *const u32) -> *const [u8] { + debug x => _1; + let mut _0: *const [u8]; + let _2: *const [u8; 4]; + let mut _3: *const u32; + let mut _5: *const [u8; 4]; + let mut _7: *const u8; + let mut _8: *const (); + scope 1 { + debug x => _2; + let _4: *const u8; + scope 2 { + debug x => _4; + let _6: *const (); + scope 3 { + debug x => _6; + } + } + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = _1; +- _2 = move _3 as *const [u8; 4] (PtrToPtr); ++ _2 = _1 as *const [u8; 4] (PtrToPtr); + StorageDead(_3); +- StorageLive(_4); ++ nop; + StorageLive(_5); + _5 = _2; +- _4 = move _5 as *const u8 (PtrToPtr); ++ _4 = _1 as *const u8 (PtrToPtr); + StorageDead(_5); +- StorageLive(_6); ++ nop; + StorageLive(_7); + _7 = _4; +- _6 = move _7 as *const () (PtrToPtr); ++ _6 = _1 as *const () (PtrToPtr); + StorageDead(_7); + StorageLive(_8); + _8 = _6; +- _0 = *const [u8] from (move _8, const 4_usize); ++ _0 = *const [u8] from (_1, const 4_usize); + StorageDead(_8); +- StorageDead(_6); +- StorageDead(_4); +- StorageDead(_2); ++ nop; ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-unwind.diff b/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-unwind.diff new file mode 100644 index 00000000000..6e5bdb16595 --- /dev/null +++ b/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-unwind.diff @@ -0,0 +1,60 @@ +- // MIR for `casts_before_aggregate_raw_ptr` before GVN ++ // MIR for `casts_before_aggregate_raw_ptr` after GVN + + fn casts_before_aggregate_raw_ptr(_1: *const u32) -> *const [u8] { + debug x => _1; + let mut _0: *const [u8]; + let _2: *const [u8; 4]; + let mut _3: *const u32; + let mut _5: *const [u8; 4]; + let mut _7: *const u8; + let mut _8: *const (); + scope 1 { + debug x => _2; + let _4: *const u8; + scope 2 { + debug x => _4; + let _6: *const (); + scope 3 { + debug x => _6; + } + } + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = _1; +- _2 = move _3 as *const [u8; 4] (PtrToPtr); ++ _2 = _1 as *const [u8; 4] (PtrToPtr); + StorageDead(_3); +- StorageLive(_4); ++ nop; + StorageLive(_5); + _5 = _2; +- _4 = move _5 as *const u8 (PtrToPtr); ++ _4 = _1 as *const u8 (PtrToPtr); + StorageDead(_5); +- StorageLive(_6); ++ nop; + StorageLive(_7); + _7 = _4; +- _6 = move _7 as *const () (PtrToPtr); ++ _6 = _1 as *const () (PtrToPtr); + StorageDead(_7); + StorageLive(_8); + _8 = _6; +- _0 = *const [u8] from (move _8, const 4_usize); ++ _0 = *const [u8] from (_1, const 4_usize); + StorageDead(_8); +- StorageDead(_6); +- StorageDead(_4); +- StorageDead(_2); ++ nop; ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-abort.diff b/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-abort.diff new file mode 100644 index 00000000000..73dbabb56b3 --- /dev/null +++ b/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-abort.diff @@ -0,0 +1,32 @@ +- // MIR for `meta_of_ref_to_slice` before GVN ++ // MIR for `meta_of_ref_to_slice` after GVN + + fn meta_of_ref_to_slice(_1: *const i32) -> usize { + debug x => _1; + let mut _0: usize; + let _2: *const [i32]; + let mut _3: *const i32; + let mut _4: *const [i32]; + scope 1 { + debug ptr => _2; + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = _1; +- _2 = *const [i32] from (move _3, const 1_usize); ++ _2 = *const [i32] from (_1, const 1_usize); + StorageDead(_3); + StorageLive(_4); + _4 = _2; +- _0 = PtrMetadata(move _4); ++ _0 = const 1_usize; + StorageDead(_4); +- StorageDead(_2); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-unwind.diff b/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-unwind.diff new file mode 100644 index 00000000000..73dbabb56b3 --- /dev/null +++ b/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-unwind.diff @@ -0,0 +1,32 @@ +- // MIR for `meta_of_ref_to_slice` before GVN ++ // MIR for `meta_of_ref_to_slice` after GVN + + fn meta_of_ref_to_slice(_1: *const i32) -> usize { + debug x => _1; + let mut _0: usize; + let _2: *const [i32]; + let mut _3: *const i32; + let mut _4: *const [i32]; + scope 1 { + debug ptr => _2; + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = _1; +- _2 = *const [i32] from (move _3, const 1_usize); ++ _2 = *const [i32] from (_1, const 1_usize); + StorageDead(_3); + StorageLive(_4); + _4 = _2; +- _0 = PtrMetadata(move _4); ++ _0 = const 1_usize; + StorageDead(_4); +- StorageDead(_2); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 9be30515283..720018f112e 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -539,7 +539,7 @@ fn slices() { #[custom_mir(dialect = "analysis")] fn duplicate_slice() -> (bool, bool) { // CHECK-LABEL: fn duplicate_slice( - mir!( + mir! { let au: u128; let bu: u128; let cu: u128; @@ -585,7 +585,7 @@ fn duplicate_slice() -> (bool, bool) { RET = (direct, indirect); Return() } - ) + } } fn repeat() { @@ -623,11 +623,13 @@ fn fn_pointers() { fn indirect_static() { static A: Option<u8> = None; - mir!({ - let ptr = Static(A); - let out = Field::<u8>(Variant(*ptr, 1), 0); - Return() - }) + mir! { + { + let ptr = Static(A); + let out = Field::<u8>(Variant(*ptr, 1), 0); + Return() + } + } } /// Verify that having constant index `u64::MAX` does not yield to an overflow in rustc. @@ -733,7 +735,7 @@ fn borrowed<T: Copy + Freeze>(x: T) { // CHECK-NEXT: _0 = opaque::<T>(_1) // CHECK: bb2: { // CHECK-NEXT: _0 = opaque::<T>(_1) - mir!( + mir! { { let a = x; let r1 = &x; @@ -748,7 +750,7 @@ fn borrowed<T: Copy + Freeze>(x: T) { ret = { Return() } - ) + } } /// Generic type `T` is not known to be `Freeze`, so shared borrows may be mutable. @@ -763,7 +765,7 @@ fn non_freeze<T: Copy>(x: T) { // CHECK-NEXT: _0 = opaque::<T>(_2) // CHECK: bb2: { // CHECK-NEXT: _0 = opaque::<T>((*_3)) - mir!( + mir! { { let a = x; let r1 = &x; @@ -778,7 +780,40 @@ fn non_freeze<T: Copy>(x: T) { ret = { Return() } - ) + } +} + +// Check that we can const-prop into `from_raw_parts` +fn slice_const_length(x: &[i32]) -> *const [i32] { + // CHECK-LABEL: fn slice_const_length( + // CHECK: _0 = *const [i32] from ({{_[0-9]+}}, const 123_usize); + let ptr = x.as_ptr(); + let len = 123; + std::intrinsics::aggregate_raw_ptr(ptr, len) +} + +fn meta_of_ref_to_slice(x: *const i32) -> usize { + // CHECK-LABEL: fn meta_of_ref_to_slice + // CHECK: _0 = const 1_usize + let ptr: *const [i32] = std::intrinsics::aggregate_raw_ptr(x, 1); + std::intrinsics::ptr_metadata(ptr) +} + +fn slice_from_raw_parts_as_ptr(x: *const u16, n: usize) -> (*const u16, *const f32) { + // CHECK-LABEL: fn slice_from_raw_parts_as_ptr + // CHECK: _8 = _1 as *const f32 (PtrToPtr); + // CHECK: _0 = (_1, move _8); + let ptr: *const [u16] = std::intrinsics::aggregate_raw_ptr(x, n); + (ptr as *const u16, ptr as *const f32) +} + +fn casts_before_aggregate_raw_ptr(x: *const u32) -> *const [u8] { + // CHECK-LABEL: fn casts_before_aggregate_raw_ptr + // CHECK: _0 = *const [u8] from (_1, const 4_usize); + let x = x as *const [u8; 4]; + let x = x as *const u8; + let x = x as *const (); + std::intrinsics::aggregate_raw_ptr(x, 4) } fn main() { @@ -805,6 +840,9 @@ fn main() { wide_ptr_integer(); borrowed(5); non_freeze(5); + slice_const_length(&[1]); + meta_of_ref_to_slice(&42); + slice_from_raw_parts_as_ptr(&123, 456); } #[inline(never)] @@ -838,3 +876,7 @@ fn identity<T>(x: T) -> T { // EMIT_MIR gvn.wide_ptr_integer.GVN.diff // EMIT_MIR gvn.borrowed.GVN.diff // EMIT_MIR gvn.non_freeze.GVN.diff +// EMIT_MIR gvn.slice_const_length.GVN.diff +// EMIT_MIR gvn.meta_of_ref_to_slice.GVN.diff +// EMIT_MIR gvn.slice_from_raw_parts_as_ptr.GVN.diff +// EMIT_MIR gvn.casts_before_aggregate_raw_ptr.GVN.diff diff --git a/tests/mir-opt/gvn.slice_const_length.GVN.panic-abort.diff b/tests/mir-opt/gvn.slice_const_length.GVN.panic-abort.diff new file mode 100644 index 00000000000..fd5fa035d81 --- /dev/null +++ b/tests/mir-opt/gvn.slice_const_length.GVN.panic-abort.diff @@ -0,0 +1,48 @@ +- // MIR for `slice_const_length` before GVN ++ // MIR for `slice_const_length` after GVN + + fn slice_const_length(_1: &[i32]) -> *const [i32] { + debug x => _1; + let mut _0: *const [i32]; + let _2: *const i32; + let mut _3: &[i32]; + let mut _5: *const i32; + let mut _6: usize; + scope 1 { + debug ptr => _2; + let _4: usize; + scope 2 { + debug len => _4; + } + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = &(*_1); + _2 = core::slice::<impl [i32]>::as_ptr(move _3) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_3); +- StorageLive(_4); ++ nop; + _4 = const 123_usize; + StorageLive(_5); + _5 = _2; + StorageLive(_6); +- _6 = _4; +- _0 = *const [i32] from (move _5, move _6); ++ _6 = const 123_usize; ++ _0 = *const [i32] from (_2, const 123_usize); + StorageDead(_6); + StorageDead(_5); +- StorageDead(_4); +- StorageDead(_2); ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.slice_const_length.GVN.panic-unwind.diff b/tests/mir-opt/gvn.slice_const_length.GVN.panic-unwind.diff new file mode 100644 index 00000000000..98945cf9724 --- /dev/null +++ b/tests/mir-opt/gvn.slice_const_length.GVN.panic-unwind.diff @@ -0,0 +1,48 @@ +- // MIR for `slice_const_length` before GVN ++ // MIR for `slice_const_length` after GVN + + fn slice_const_length(_1: &[i32]) -> *const [i32] { + debug x => _1; + let mut _0: *const [i32]; + let _2: *const i32; + let mut _3: &[i32]; + let mut _5: *const i32; + let mut _6: usize; + scope 1 { + debug ptr => _2; + let _4: usize; + scope 2 { + debug len => _4; + } + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = &(*_1); + _2 = core::slice::<impl [i32]>::as_ptr(move _3) -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_3); +- StorageLive(_4); ++ nop; + _4 = const 123_usize; + StorageLive(_5); + _5 = _2; + StorageLive(_6); +- _6 = _4; +- _0 = *const [i32] from (move _5, move _6); ++ _6 = const 123_usize; ++ _0 = *const [i32] from (_2, const 123_usize); + StorageDead(_6); + StorageDead(_5); +- StorageDead(_4); +- StorageDead(_2); ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-abort.diff b/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-abort.diff new file mode 100644 index 00000000000..75bcd2a8d72 --- /dev/null +++ b/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-abort.diff @@ -0,0 +1,51 @@ +- // MIR for `slice_from_raw_parts_as_ptr` before GVN ++ // MIR for `slice_from_raw_parts_as_ptr` after GVN + + fn slice_from_raw_parts_as_ptr(_1: *const u16, _2: usize) -> (*const u16, *const f32) { + debug x => _1; + debug n => _2; + let mut _0: (*const u16, *const f32); + let _3: *const [u16]; + let mut _4: *const u16; + let mut _5: usize; + let mut _6: *const u16; + let mut _7: *const [u16]; + let mut _8: *const f32; + let mut _9: *const [u16]; + scope 1 { + debug ptr => _3; + } + + bb0: { +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = _1; + StorageLive(_5); + _5 = _2; +- _3 = *const [u16] from (move _4, move _5); ++ _3 = *const [u16] from (_1, _2); + StorageDead(_5); + StorageDead(_4); + StorageLive(_6); + StorageLive(_7); + _7 = _3; +- _6 = move _7 as *const u16 (PtrToPtr); ++ _6 = _1; + StorageDead(_7); + StorageLive(_8); + StorageLive(_9); + _9 = _3; +- _8 = move _9 as *const f32 (PtrToPtr); ++ _8 = _1 as *const f32 (PtrToPtr); + StorageDead(_9); +- _0 = (move _6, move _8); ++ _0 = (_1, move _8); + StorageDead(_8); + StorageDead(_6); +- StorageDead(_3); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-unwind.diff b/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-unwind.diff new file mode 100644 index 00000000000..75bcd2a8d72 --- /dev/null +++ b/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-unwind.diff @@ -0,0 +1,51 @@ +- // MIR for `slice_from_raw_parts_as_ptr` before GVN ++ // MIR for `slice_from_raw_parts_as_ptr` after GVN + + fn slice_from_raw_parts_as_ptr(_1: *const u16, _2: usize) -> (*const u16, *const f32) { + debug x => _1; + debug n => _2; + let mut _0: (*const u16, *const f32); + let _3: *const [u16]; + let mut _4: *const u16; + let mut _5: usize; + let mut _6: *const u16; + let mut _7: *const [u16]; + let mut _8: *const f32; + let mut _9: *const [u16]; + scope 1 { + debug ptr => _3; + } + + bb0: { +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = _1; + StorageLive(_5); + _5 = _2; +- _3 = *const [u16] from (move _4, move _5); ++ _3 = *const [u16] from (_1, _2); + StorageDead(_5); + StorageDead(_4); + StorageLive(_6); + StorageLive(_7); + _7 = _3; +- _6 = move _7 as *const u16 (PtrToPtr); ++ _6 = _1; + StorageDead(_7); + StorageLive(_8); + StorageLive(_9); + _9 = _3; +- _8 = move _9 as *const f32 (PtrToPtr); ++ _8 = _1 as *const f32 (PtrToPtr); + StorageDead(_9); +- _0 = (move _6, move _8); ++ _0 = (_1, move _8); + StorageDead(_8); + StorageDead(_6); +- StorageDead(_3); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/inline/inline_cycle.rs b/tests/mir-opt/inline/inline_cycle.rs index 1826e38f894..651112ccfd7 100644 --- a/tests/mir-opt/inline/inline_cycle.rs +++ b/tests/mir-opt/inline/inline_cycle.rs @@ -32,7 +32,6 @@ impl<T: Call> Call for A<T> { } } - impl<T: Call> Call for B<T> { #[inline] fn call() { diff --git a/tests/mir-opt/inline/inline_cycle_generic.rs b/tests/mir-opt/inline/inline_cycle_generic.rs index 667bf7f9254..64f208b1c70 100644 --- a/tests/mir-opt/inline/inline_cycle_generic.rs +++ b/tests/mir-opt/inline/inline_cycle_generic.rs @@ -26,7 +26,6 @@ impl Call for A { } } - impl<T: Call> Call for B<T> { #[inline] fn call() { diff --git a/tests/mir-opt/inline/inline_options.rs b/tests/mir-opt/inline/inline_options.rs index 7d7c4f718bd..bd9e0e2d207 100644 --- a/tests/mir-opt/inline/inline_options.rs +++ b/tests/mir-opt/inline/inline_options.rs @@ -16,8 +16,16 @@ fn main() { // Cost is approximately 3 * 25 + 5 = 80. #[inline] -pub fn not_inlined() { g(); g(); g(); } -pub fn inlined<T>() { g(); g(); g(); } +pub fn not_inlined() { + g(); + g(); + g(); +} +pub fn inlined<T>() { + g(); + g(); + g(); +} #[inline(never)] fn g() {} diff --git a/tests/mir-opt/inline/inline_specialization.rs b/tests/mir-opt/inline/inline_specialization.rs index 6453abc0081..b9d40aca3a4 100644 --- a/tests/mir-opt/inline/inline_specialization.rs +++ b/tests/mir-opt/inline/inline_specialization.rs @@ -5,7 +5,7 @@ fn main() { // CHECK-LABEL: fn main( // CHECK: (inlined <Vec<()> as Foo>::bar) - let x = <Vec::<()> as Foo>::bar(); + let x = <Vec<()> as Foo>::bar(); } trait Foo { @@ -14,5 +14,7 @@ trait Foo { impl<T> Foo for Vec<T> { #[inline(always)] - default fn bar() -> u32 { 123 } + default fn bar() -> u32 { + 123 + } } diff --git a/tests/mir-opt/inline/issue_106141.outer.Inline.panic-abort.diff b/tests/mir-opt/inline/issue_106141.outer.Inline.panic-abort.diff index 24e5587f963..2ab79cc2a50 100644 --- a/tests/mir-opt/inline/issue_106141.outer.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/issue_106141.outer.Inline.panic-abort.diff @@ -8,7 +8,7 @@ + let mut _2: bool; + let mut _3: bool; + scope 2 { -+ debug buffer => const inner::promoted[0]; ++ debug buffer => _1; + scope 3 { + debug index => _0; + } diff --git a/tests/mir-opt/inline/issue_106141.outer.Inline.panic-unwind.diff b/tests/mir-opt/inline/issue_106141.outer.Inline.panic-unwind.diff index 4eb8a5c9847..4d96a862885 100644 --- a/tests/mir-opt/inline/issue_106141.outer.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/issue_106141.outer.Inline.panic-unwind.diff @@ -8,7 +8,7 @@ + let mut _2: bool; + let mut _3: bool; + scope 2 { -+ debug buffer => const inner::promoted[0]; ++ debug buffer => _1; + scope 3 { + debug index => _0; + } diff --git a/tests/mir-opt/inline/issue_106141.rs b/tests/mir-opt/inline/issue_106141.rs index 1cca7d76b25..d311ad4527f 100644 --- a/tests/mir-opt/inline/issue_106141.rs +++ b/tests/mir-opt/inline/issue_106141.rs @@ -19,11 +19,7 @@ fn inner() -> usize { // CHECK: = {{.*}}[_0]; let buffer = &[true]; let index = index(); - if buffer[index] { - index - } else { - 0 - } + if buffer[index] { index } else { 0 } } fn main() { diff --git a/tests/mir-opt/inline/issue_76997_inline_scopes_parenting.rs b/tests/mir-opt/inline/issue_76997_inline_scopes_parenting.rs index 75772c16127..021af7f81bb 100644 --- a/tests/mir-opt/inline/issue_76997_inline_scopes_parenting.rs +++ b/tests/mir-opt/inline/issue_76997_inline_scopes_parenting.rs @@ -13,6 +13,9 @@ fn main() { // CHECK-NEXT: } // CHECK-NEXT: } // CHECK-NEXT: } - let f = |x| { let y = x; y }; + let f = |x| { + let y = x; + y + }; f(()) } diff --git a/tests/mir-opt/instsimplify/combine_array_len.rs b/tests/mir-opt/instsimplify/combine_array_len.rs index 86455e8b52d..f12284f6482 100644 --- a/tests/mir-opt/instsimplify/combine_array_len.rs +++ b/tests/mir-opt/instsimplify/combine_array_len.rs @@ -7,9 +7,9 @@ fn norm2(x: [f32; 2]) -> f32 { // CHECK-NOT: Len( let a = x[0]; let b = x[1]; - a*a + b*b + a * a + b * b } fn main() { - assert_eq!(norm2([3.0, 4.0]), 5.0*5.0); + assert_eq!(norm2([3.0, 4.0]), 5.0 * 5.0); } diff --git a/tests/mir-opt/instsimplify/combine_transmutes.rs b/tests/mir-opt/instsimplify/combine_transmutes.rs index 0be7466001f..c3622c20697 100644 --- a/tests/mir-opt/instsimplify/combine_transmutes.rs +++ b/tests/mir-opt/instsimplify/combine_transmutes.rs @@ -5,7 +5,7 @@ #![feature(custom_mir)] use std::intrinsics::mir::*; -use std::mem::{MaybeUninit, ManuallyDrop, transmute}; +use std::mem::{transmute, ManuallyDrop, MaybeUninit}; // EMIT_MIR combine_transmutes.identity_transmutes.InstSimplify.diff pub unsafe fn identity_transmutes() { @@ -61,4 +61,7 @@ pub unsafe fn adt_transmutes() { let _a: ManuallyDrop<String> = transmute(MaybeUninit::<String>::uninit()); } -pub union Union32 { u32: u32, i32: i32 } +pub union Union32 { + u32: u32, + i32: i32, +} diff --git a/tests/mir-opt/instsimplify/duplicate_switch_targets.rs b/tests/mir-opt/instsimplify/duplicate_switch_targets.rs index 454728249b1..a47d9d5a71d 100644 --- a/tests/mir-opt/instsimplify/duplicate_switch_targets.rs +++ b/tests/mir-opt/instsimplify/duplicate_switch_targets.rs @@ -10,7 +10,7 @@ use std::intrinsics::mir::*; pub unsafe fn assert_zero(x: u8) -> u8 { // CHECK-LABEL: fn assert_zero( // CHECK: switchInt({{.*}}) -> [0: {{bb.*}}, otherwise: {{bb.*}}] - mir!( + mir! { { match x { 0 => retblock, @@ -25,5 +25,5 @@ pub unsafe fn assert_zero(x: u8) -> u8 { RET = x; Return() } - ) + } } diff --git a/tests/mir-opt/issue_104451_unwindable_intrinsics.rs b/tests/mir-opt/issue_104451_unwindable_intrinsics.rs index cd068f12236..80655a583c3 100644 --- a/tests/mir-opt/issue_104451_unwindable_intrinsics.rs +++ b/tests/mir-opt/issue_104451_unwindable_intrinsics.rs @@ -5,9 +5,7 @@ // EMIT_MIR issue_104451_unwindable_intrinsics.main.AbortUnwindingCalls.after.mir fn main() { - unsafe { - core::intrinsics::const_eval_select((), ow_ct, ow_ct) - } + unsafe { core::intrinsics::const_eval_select((), ow_ct, ow_ct) } } const fn ow_ct() -> ! { diff --git a/tests/mir-opt/issue_41110.rs b/tests/mir-opt/issue_41110.rs index 38602d5eaef..5d042815f3b 100644 --- a/tests/mir-opt/issue_41110.rs +++ b/tests/mir-opt/issue_41110.rs @@ -3,7 +3,6 @@ // check that we don't emit multiple drop flags when they are not needed. - // EMIT_MIR issue_41110.main.ElaborateDrops.diff fn main() { let x = S.other(S.id()); @@ -21,11 +20,12 @@ pub fn test() { struct S; impl Drop for S { - fn drop(&mut self) { - } + fn drop(&mut self) {} } impl S { - fn id(self) -> Self { self } + fn id(self) -> Self { + self + } fn other(self, s: Self) {} } diff --git a/tests/mir-opt/issue_41697.rs b/tests/mir-opt/issue_41697.rs index 92d382c3940..b031f1dc720 100644 --- a/tests/mir-opt/issue_41697.rs +++ b/tests/mir-opt/issue_41697.rs @@ -14,9 +14,8 @@ trait Foo { fn get(&self) -> [u8; 2]; } - // EMIT_MIR issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir -impl Foo for [u8; 1+1] { +impl Foo for [u8; 1 + 1] { fn get(&self) -> [u8; 2] { *self } @@ -33,7 +32,7 @@ fn unsize_nested_fat_ptr(x: Arc<Foo + Send>) -> Arc<Foo> { } fn main() { - let x: Box<Bar<Foo + Send>> = Box::new(Bar([1,2])); + let x: Box<Bar<Foo + Send>> = Box::new(Bar([1, 2])); assert_eq!(unsize_fat_ptr(&*x).0.get(), [1, 2]); let x: Arc<Foo + Send> = Arc::new([3, 4]); diff --git a/tests/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir b/tests/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir index 7d2e97f8d56..27a5a8dd552 100644 --- a/tests/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir +++ b/tests/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir @@ -1,6 +1,6 @@ -// MIR for `<impl at $DIR/issue_41697.rs:19:1: 19:23>::{constant#0}` after SimplifyCfg-promote-consts +// MIR for `<impl at $DIR/issue_41697.rs:18:1: 18:25>::{constant#0}` after SimplifyCfg-promote-consts -<impl at $DIR/issue_41697.rs:19:1: 19:23>::{constant#0}: usize = { +<impl at $DIR/issue_41697.rs:18:1: 18:25>::{constant#0}: usize = { let mut _0: usize; let mut _1: (usize, bool); diff --git a/tests/mir-opt/issue_41888.rs b/tests/mir-opt/issue_41888.rs index 70b20218633..1744d9f8570 100644 --- a/tests/mir-opt/issue_41888.rs +++ b/tests/mir-opt/issue_41888.rs @@ -15,11 +15,13 @@ fn main() { } } -fn cond() -> bool { false } +fn cond() -> bool { + false +} struct K; enum E { F(K), - G(Box<E>) + G(Box<E>), } diff --git a/tests/mir-opt/issue_72181.rs b/tests/mir-opt/issue_72181.rs index 3748c2af83d..dea8ecbd3ec 100644 --- a/tests/mir-opt/issue_72181.rs +++ b/tests/mir-opt/issue_72181.rs @@ -9,16 +9,18 @@ enum Never {} union Foo { a: u64, - b: Never + b: Never, } - // EMIT_MIR issue_72181.foo.built.after.mir -fn foo(xs: [(Never, u32); 1]) -> u32 { xs[0].1 } +fn foo(xs: [(Never, u32); 1]) -> u32 { + xs[0].1 +} // EMIT_MIR issue_72181.bar.built.after.mir -fn bar([(_, x)]: [(Never, u32); 1]) -> u32 { x } - +fn bar([(_, x)]: [(Never, u32); 1]) -> u32 { + x +} // EMIT_MIR issue_72181.main.built.after.mir fn main() { diff --git a/tests/mir-opt/issue_72181_1.rs b/tests/mir-opt/issue_72181_1.rs index 32e946559d7..5c8346166ae 100644 --- a/tests/mir-opt/issue_72181_1.rs +++ b/tests/mir-opt/issue_72181_1.rs @@ -14,9 +14,7 @@ fn f(v: Void) -> ! { // EMIT_MIR issue_72181_1.main.built.after.mir fn main() { - let v: Void = unsafe { - std::mem::transmute::<(), Void>(()) - }; + let v: Void = unsafe { std::mem::transmute::<(), Void>(()) }; f(v); } diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff index b2539f391d1..1f88339b586 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff @@ -29,8 +29,8 @@ _3 = &_4; _2 = move _3 as &[T] (PointerCoercion(Unsize)); StorageDead(_3); - _5 = const 3_usize; - _6 = const true; + nop; + nop; goto -> bb2; } diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff index ff7f12c093c..19a581ba3f0 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff @@ -29,8 +29,8 @@ _3 = &_4; _2 = move _3 as &[T] (PointerCoercion(Unsize)); StorageDead(_3); - _5 = const 3_usize; - _6 = const true; + nop; + nop; goto -> bb2; } diff --git a/tests/mir-opt/issue_91633.rs b/tests/mir-opt/issue_91633.rs index f7d59f5adfb..d24c2e19aa7 100644 --- a/tests/mir-opt/issue_91633.rs +++ b/tests/mir-opt/issue_91633.rs @@ -1,32 +1,30 @@ // skip-filecheck //@ compile-flags: -Z mir-opt-level=0 // EMIT_MIR issue_91633.hey.built.after.mir -fn hey<T> (it: &[T]) - where - [T] : std::ops::Index<usize>, - { - let _ = &it[0]; - } +fn hey<T>(it: &[T]) +where + [T]: std::ops::Index<usize>, +{ + let _ = &it[0]; +} // EMIT_MIR issue_91633.bar.built.after.mir -fn bar<T> (it: Box<[T]>) - where - [T] : std::ops::Index<usize>, - { - let _ = it[0]; - } +fn bar<T>(it: Box<[T]>) +where + [T]: std::ops::Index<usize>, +{ + let _ = it[0]; +} // EMIT_MIR issue_91633.fun.built.after.mir -fn fun<T> (it: &[T]) -> &T - { - let f = &it[0]; - f - } +fn fun<T>(it: &[T]) -> &T { + let f = &it[0]; + f +} // EMIT_MIR issue_91633.foo.built.after.mir -fn foo<T: Clone> (it: Box<[T]>) -> T - { - let f = it[0].clone(); - f - } - fn main(){} +fn foo<T: Clone>(it: Box<[T]>) -> T { + let f = it[0].clone(); + f +} +fn main() {} diff --git a/tests/mir-opt/issue_99325.main.built.after.32bit.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir index 0b0bac73e9f..b7a054b5d54 100644 --- a/tests/mir-opt/issue_99325.main.built.after.32bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir @@ -2,7 +2,7 @@ | User Type Annotations | 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &'static [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir index 0b0bac73e9f..b7a054b5d54 100644 --- a/tests/mir-opt/issue_99325.main.built.after.64bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir @@ -2,7 +2,7 @@ | User Type Annotations | 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &'static [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/issues/issue_75439.rs b/tests/mir-opt/issues/issue_75439.rs index 8c710a33aa8..ea763dd1b10 100644 --- a/tests/mir-opt/issues/issue_75439.rs +++ b/tests/mir-opt/issues/issue_75439.rs @@ -8,11 +8,7 @@ pub fn foo(bytes: [u8; 16]) -> Option<[u8; 4]> { // big endian `u32`s let dwords: [u32; 4] = unsafe { transmute(bytes) }; const FF: u32 = 0x0000_ffff_u32.to_be(); - if let [0, 0, 0 | FF, ip] = dwords { - Some(unsafe { transmute(ip) }) - } else { - None - } + if let [0, 0, 0 | FF, ip] = dwords { Some(unsafe { transmute(ip) }) } else { None } } fn main() { diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs index 57f4e4a2654..b4c13371680 100644 --- a/tests/mir-opt/jump_threading.rs +++ b/tests/mir-opt/jump_threading.rs @@ -157,7 +157,7 @@ fn custom_discr(x: bool) -> u8 { #[custom_mir(dialect = "runtime", phase = "post-cleanup")] fn multiple_match(x: u8) -> u8 { // CHECK-LABEL: fn multiple_match( - mir!( + mir! { { // CHECK: bb0: { // CHECK: switchInt([[x:_.*]]) -> [3: bb1, otherwise: bb2]; @@ -220,7 +220,7 @@ fn multiple_match(x: u8) -> u8 { RET = 11; Return() } - ) + } } /// Both 1-3-4 and 2-3-4 are threadable. As 1 and 2 are the only predecessors of 3, @@ -228,7 +228,7 @@ fn multiple_match(x: u8) -> u8 { #[custom_mir(dialect = "runtime", phase = "post-cleanup")] fn duplicate_chain(x: bool) -> u8 { // CHECK-LABEL: fn duplicate_chain( - mir!( + mir! { let a: u8; { // CHECK: bb0: { @@ -278,7 +278,7 @@ fn duplicate_chain(x: bool) -> u8 { RET = 9; Return() } - ) + } } #[rustc_layout_scalar_valid_range_start(1)] @@ -292,7 +292,7 @@ fn mutate_discriminant() -> u8 { // CHECK-NOT: goto -> {{bb.*}}; // CHECK: switchInt( // CHECK-NOT: goto -> {{bb.*}}; - mir!( + mir! { let x: Option<NonZeroUsize>; { SetDiscriminant(x, 1); @@ -313,7 +313,7 @@ fn mutate_discriminant() -> u8 { RET = 2; Unreachable() } - ) + } } /// Verify that we do not try to reason when there are mutable pointers involved. @@ -330,11 +330,7 @@ fn mutable_ref() -> bool { let a = std::ptr::addr_of_mut!(x); x = 7; unsafe { *a = 8 }; - if x == 7 { - true - } else { - false - } + if x == 7 { true } else { false } } /// This function has 2 TOs: 1-3-4 and 0-1-3-4-6. @@ -342,7 +338,7 @@ fn mutable_ref() -> bool { #[custom_mir(dialect = "runtime", phase = "post-cleanup")] fn renumbered_bb(x: bool) -> u8 { // CHECK-LABEL: fn renumbered_bb( - mir!( + mir! { let a: bool; let b: bool; { @@ -398,7 +394,7 @@ fn renumbered_bb(x: bool) -> u8 { // Duplicate of bb4. // CHECK: bb9: { // CHECK-NEXT: goto -> bb6; - ) + } } /// This function has 3 TOs: 1-4-5, 0-1-4-7-5-8 and 3-4-7-5-6 @@ -408,7 +404,7 @@ fn renumbered_bb(x: bool) -> u8 { #[custom_mir(dialect = "runtime", phase = "post-cleanup")] fn disappearing_bb(x: u8) -> u8 { // CHECK-LABEL: fn disappearing_bb( - mir!( + mir! { let a: bool; let b: bool; { @@ -450,7 +446,7 @@ fn disappearing_bb(x: u8) -> u8 { // CHECK: goto -> bb5; // CHECK: bb10: { // CHECK: goto -> bb6; - ) + } } /// Verify that we can thread jumps when we assign from an aggregate constant. @@ -461,18 +457,14 @@ fn aggregate(x: u8) -> u8 { const FOO: (u8, u8) = (5, 13); let (a, b) = FOO; - if a == 7 { - b - } else { - a - } + if a == 7 { b } else { a } } /// Verify that we can leverage the existence of an `Assume` terminator. #[custom_mir(dialect = "runtime", phase = "post-cleanup")] fn assume(a: u8, b: bool) -> u8 { // CHECK-LABEL: fn assume( - mir!( + mir! { { // CHECK: bb0: { // CHECK-NEXT: switchInt(_1) -> [7: bb1, otherwise: bb2] @@ -511,7 +503,7 @@ fn assume(a: u8, b: bool) -> u8 { } // CHECK: bb6: { // CHECK-NEXT: goto -> bb5; - ) + } } fn main() { diff --git a/tests/mir-opt/lower_array_len.rs b/tests/mir-opt/lower_array_len.rs index 1c30c4c89b9..62fc9ef67d6 100644 --- a/tests/mir-opt/lower_array_len.rs +++ b/tests/mir-opt/lower_array_len.rs @@ -7,11 +7,7 @@ pub fn array_bound<const N: usize>(index: usize, slice: &[u8; N]) -> u8 { // CHECK-LABEL: fn array_bound( // CHECK: [[len:_.*]] = const N; // CHECK: Lt(move {{_.*}}, move [[len]]); - if index < slice.len() { - slice[index] - } else { - 42 - } + if index < slice.len() { slice[index] } else { 42 } } // EMIT_MIR lower_array_len.array_bound_mut.NormalizeArrayLen.diff diff --git a/tests/mir-opt/lower_slice_len.rs b/tests/mir-opt/lower_slice_len.rs index b82094dc18f..6fd7e4bf72c 100644 --- a/tests/mir-opt/lower_slice_len.rs +++ b/tests/mir-opt/lower_slice_len.rs @@ -5,11 +5,7 @@ pub fn bound(index: usize, slice: &[u8]) -> u8 { // CHECK-LABEL: fn bound( // CHECK-NOT: ::len( - if index < slice.len() { - slice[index] - } else { - 42 - } + if index < slice.len() { slice[index] } else { 42 } } fn main() { diff --git a/tests/mir-opt/matches_reduce_branches.rs b/tests/mir-opt/matches_reduce_branches.rs index fa466220b65..176d68bcd40 100644 --- a/tests/mir-opt/matches_reduce_branches.rs +++ b/tests/mir-opt/matches_reduce_branches.rs @@ -88,7 +88,7 @@ fn match_u8_i16(i: EnumAu8) -> i16 { fn match_u8_i16_2(i: EnumAu8) -> i16 { // CHECK-LABEL: fn match_u8_i16_2( // CHECK: switchInt - mir!( + mir! { { let a = Discriminant(i); match a { @@ -110,7 +110,7 @@ fn match_u8_i16_2(i: EnumAu8) -> i16 { ret = { Return() } - ) + } } // EMIT_MIR matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff @@ -158,7 +158,7 @@ fn match_u8_u16(i: EnumBu8) -> u16 { fn match_u8_u16_2(i: EnumBu8) -> i16 { // CHECK-LABEL: fn match_u8_u16_2( // CHECK: switchInt - mir!( + mir! { { let a = Discriminant(i); match a { @@ -187,7 +187,7 @@ fn match_u8_u16_2(i: EnumBu8) -> i16 { ret = { Return() } - ) + } } #[repr(i8)] diff --git a/tests/mir-opt/matches_u8.rs b/tests/mir-opt/matches_u8.rs index f0be82d0257..86d64625674 100644 --- a/tests/mir-opt/matches_u8.rs +++ b/tests/mir-opt/matches_u8.rs @@ -1,7 +1,6 @@ // skip-filecheck //@ test-mir-pass: MatchBranchSimplification - // EMIT_MIR matches_u8.exhaustive_match.MatchBranchSimplification.diff // EMIT_MIR matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff @@ -27,9 +26,9 @@ pub fn exhaustive_match_i8(e: E) -> i8 { } fn main() { - assert_eq!(exhaustive_match(E::A), 0); - assert_eq!(exhaustive_match(E::B), 1); + assert_eq!(exhaustive_match(E::A), 0); + assert_eq!(exhaustive_match(E::B), 1); - assert_eq!(exhaustive_match_i8(E::A), 0); - assert_eq!(exhaustive_match_i8(E::B), 1); + assert_eq!(exhaustive_match_i8(E::A), 0); + assert_eq!(exhaustive_match_i8(E::B), 1); } diff --git a/tests/mir-opt/nll/named_lifetimes_basic.rs b/tests/mir-opt/nll/named_lifetimes_basic.rs index cc838537003..93f4a8bfd59 100644 --- a/tests/mir-opt/nll/named_lifetimes_basic.rs +++ b/tests/mir-opt/nll/named_lifetimes_basic.rs @@ -10,7 +10,8 @@ #![allow(warnings)] // EMIT_MIR named_lifetimes_basic.use_x.nll.0.mir -fn use_x<'a, 'b: 'a, 'c>(w: &'a mut i32, x: &'b u32, y: &'a u32, z: &'c u32) -> bool { true } - -fn main() { +fn use_x<'a, 'b: 'a, 'c>(w: &'a mut i32, x: &'b u32, y: &'a u32, z: &'c u32) -> bool { + true } + +fn main() {} diff --git a/tests/mir-opt/nrvo_miscompile_111005.rs b/tests/mir-opt/nrvo_miscompile_111005.rs index 18814b0678f..03008fa8191 100644 --- a/tests/mir-opt/nrvo_miscompile_111005.rs +++ b/tests/mir-opt/nrvo_miscompile_111005.rs @@ -10,12 +10,14 @@ use core::intrinsics::mir::*; // EMIT_MIR nrvo_miscompile_111005.wrong.RenameReturnPlace.diff #[custom_mir(dialect = "runtime", phase = "initial")] pub fn wrong(arg: char) -> char { - mir!({ - let temp = arg; - RET = temp; - temp = 'b'; - Return() - }) + mir! { + { + let temp = arg; + RET = temp; + temp = 'b'; + Return() + } + } } fn main() { diff --git a/tests/mir-opt/nrvo_simple.rs b/tests/mir-opt/nrvo_simple.rs index 5d2894a704a..df540472e1c 100644 --- a/tests/mir-opt/nrvo_simple.rs +++ b/tests/mir-opt/nrvo_simple.rs @@ -10,5 +10,7 @@ fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] { } fn main() { - let _ = nrvo(|buf| { buf[4] = 4; }); + let _ = nrvo(|buf| { + buf[4] = 4; + }); } diff --git a/tests/mir-opt/packed_struct_drop_aligned.rs b/tests/mir-opt/packed_struct_drop_aligned.rs index dff941c4fa0..3abc6426e7f 100644 --- a/tests/mir-opt/packed_struct_drop_aligned.rs +++ b/tests/mir-opt/packed_struct_drop_aligned.rs @@ -1,7 +1,6 @@ // skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY - // EMIT_MIR packed_struct_drop_aligned.main.SimplifyCfg-pre-optimizations.after.mir fn main() { let mut x = Packed(Aligned(Droppy(0))); diff --git a/tests/mir-opt/pre-codegen/intrinsics.rs b/tests/mir-opt/pre-codegen/intrinsics.rs index e5c059cda12..0482b85e95f 100644 --- a/tests/mir-opt/pre-codegen/intrinsics.rs +++ b/tests/mir-opt/pre-codegen/intrinsics.rs @@ -12,7 +12,6 @@ pub fn f_unit() { f_dispatch(()); } - // EMIT_MIR intrinsics.f_u64.PreCodegen.after.mir pub fn f_u64() { f_dispatch(0u64); @@ -28,8 +27,7 @@ pub fn f_dispatch<T>(t: T) { } #[inline(never)] -pub fn f_zst<T>(_t: T) { -} +pub fn f_zst<T>(_t: T) {} #[inline(never)] pub fn f_non_zst<T>(_t: T) {} diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff index 17d83752fc1..465cb1a9b1f 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff @@ -23,16 +23,15 @@ let mut _12: isize; let _13: std::alloc::AllocError; let mut _14: !; - let _15: &str; - let mut _16: &dyn std::fmt::Debug; - let mut _17: &std::alloc::AllocError; + let mut _15: &dyn std::fmt::Debug; + let mut _16: &std::alloc::AllocError; scope 7 { } scope 8 { } } scope 9 (inlined NonNull::<[u8]>::as_ptr) { - let mut _18: *const [u8]; + let mut _17: *const [u8]; } } scope 3 (inlined #[track_caller] Option::<Layout>::unwrap) { @@ -87,36 +86,33 @@ StorageDead(_8); StorageDead(_7); StorageLive(_12); - StorageLive(_15); _12 = discriminant(_6); switchInt(move _12) -> [0: bb6, 1: bb5, otherwise: bb1]; } bb5: { - _15 = const "called `Result::unwrap()` on an `Err` value"; + StorageLive(_15); StorageLive(_16); - StorageLive(_17); - _17 = &_13; - _16 = move _17 as &dyn std::fmt::Debug (PointerCoercion(Unsize)); - StorageDead(_17); - _14 = result::unwrap_failed(move _15, move _16) -> unwind unreachable; + _16 = &_13; + _15 = move _16 as &dyn std::fmt::Debug (PointerCoercion(Unsize)); + StorageDead(_16); + _14 = result::unwrap_failed(const "called `Result::unwrap()` on an `Err` value", move _15) -> unwind unreachable; } bb6: { _5 = move ((_6 as Ok).0: std::ptr::NonNull<[u8]>); - StorageDead(_15); StorageDead(_12); StorageDead(_6); -- StorageLive(_18); +- StorageLive(_17); + nop; - _18 = (_5.0: *const [u8]); -- _4 = move _18 as *mut [u8] (PtrToPtr); -- StorageDead(_18); -+ _4 = _18 as *mut [u8] (PtrToPtr); + _17 = (_5.0: *const [u8]); +- _4 = move _17 as *mut [u8] (PtrToPtr); +- StorageDead(_17); ++ _4 = _17 as *mut [u8] (PtrToPtr); + nop; StorageDead(_5); - _3 = move _4 as *mut u8 (PtrToPtr); -+ _3 = _18 as *mut u8 (PtrToPtr); ++ _3 = _17 as *mut u8 (PtrToPtr); StorageDead(_4); StorageDead(_3); - StorageDead(_1); diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff index 1cf950402c3..925d8997b8a 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff @@ -23,16 +23,15 @@ let mut _12: isize; let _13: std::alloc::AllocError; let mut _14: !; - let _15: &str; - let mut _16: &dyn std::fmt::Debug; - let mut _17: &std::alloc::AllocError; + let mut _15: &dyn std::fmt::Debug; + let mut _16: &std::alloc::AllocError; scope 7 { } scope 8 { } } scope 9 (inlined NonNull::<[u8]>::as_ptr) { - let mut _18: *const [u8]; + let mut _17: *const [u8]; } } scope 3 (inlined #[track_caller] Option::<Layout>::unwrap) { @@ -87,36 +86,33 @@ StorageDead(_8); StorageDead(_7); StorageLive(_12); - StorageLive(_15); _12 = discriminant(_6); switchInt(move _12) -> [0: bb6, 1: bb5, otherwise: bb1]; } bb5: { - _15 = const "called `Result::unwrap()` on an `Err` value"; + StorageLive(_15); StorageLive(_16); - StorageLive(_17); - _17 = &_13; - _16 = move _17 as &dyn std::fmt::Debug (PointerCoercion(Unsize)); - StorageDead(_17); - _14 = result::unwrap_failed(move _15, move _16) -> unwind unreachable; + _16 = &_13; + _15 = move _16 as &dyn std::fmt::Debug (PointerCoercion(Unsize)); + StorageDead(_16); + _14 = result::unwrap_failed(const "called `Result::unwrap()` on an `Err` value", move _15) -> unwind unreachable; } bb6: { _5 = move ((_6 as Ok).0: std::ptr::NonNull<[u8]>); - StorageDead(_15); StorageDead(_12); StorageDead(_6); -- StorageLive(_18); +- StorageLive(_17); + nop; - _18 = (_5.0: *const [u8]); -- _4 = move _18 as *mut [u8] (PtrToPtr); -- StorageDead(_18); -+ _4 = _18 as *mut [u8] (PtrToPtr); + _17 = (_5.0: *const [u8]); +- _4 = move _17 as *mut [u8] (PtrToPtr); +- StorageDead(_17); ++ _4 = _17 as *mut [u8] (PtrToPtr); + nop; StorageDead(_5); - _3 = move _4 as *mut u8 (PtrToPtr); -+ _3 = _18 as *mut u8 (PtrToPtr); ++ _3 = _17 as *mut u8 (PtrToPtr); StorageDead(_4); StorageDead(_3); - StorageDead(_1); diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.rs b/tests/mir-opt/pre-codegen/optimizes_into_variable.rs index 7a1fb1e76c0..de5e2d5c312 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.rs +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.rs @@ -15,5 +15,5 @@ struct Point { fn main() { let x = 2 + 2; let y = [0, 1, 2, 3, 4, 5][3]; - let z = (Point { x: 12, y: 42}).y; + let z = (Point { x: 12, y: 42 }).y; } diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir index 2c6d93e10c1..2f6139712ff 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir @@ -12,8 +12,7 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { scope 3 (inlined std::ptr::const_ptr::<impl *const u8>::add) { } scope 4 (inlined std::ptr::const_ptr::<impl *const u8>::with_metadata_of::<[u32]>) { - let mut _5: *const (); - let mut _6: usize; + let mut _5: usize; scope 5 (inlined std::ptr::metadata::<[u32]>) { } scope 6 (inlined std::ptr::from_raw_parts::<[u32], ()>) { @@ -28,11 +27,8 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { _4 = Offset(_3, _2); StorageDead(_3); StorageLive(_5); - _5 = _4 as *const () (PtrToPtr); - StorageLive(_6); - _6 = PtrMetadata(_1); - _0 = *const [u32] from (_5, _6); - StorageDead(_6); + _5 = PtrMetadata(_1); + _0 = *const [u32] from (_4, _5); StorageDead(_5); StorageDead(_4); return; diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir index 2c6d93e10c1..2f6139712ff 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir @@ -12,8 +12,7 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { scope 3 (inlined std::ptr::const_ptr::<impl *const u8>::add) { } scope 4 (inlined std::ptr::const_ptr::<impl *const u8>::with_metadata_of::<[u32]>) { - let mut _5: *const (); - let mut _6: usize; + let mut _5: usize; scope 5 (inlined std::ptr::metadata::<[u32]>) { } scope 6 (inlined std::ptr::from_raw_parts::<[u32], ()>) { @@ -28,11 +27,8 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { _4 = Offset(_3, _2); StorageDead(_3); StorageLive(_5); - _5 = _4 as *const () (PtrToPtr); - StorageLive(_6); - _6 = PtrMetadata(_1); - _0 = *const [u32] from (_5, _6); - StorageDead(_6); + _5 = PtrMetadata(_1); + _0 = *const [u32] from (_4, _5); StorageDead(_5); StorageDead(_4); return; diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir index 04fb6b838f0..8d47e63eff2 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir @@ -20,11 +20,13 @@ fn demo_byte_add_thin(_1: *const u32, _2: usize) -> *const u32 { } bb0: { + StorageLive(_4); StorageLive(_3); _3 = _1 as *const u8 (PtrToPtr); _4 = Offset(_3, _2); StorageDead(_3); _0 = _4 as *const u32 (PtrToPtr); + StorageDead(_4); return; } } diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir index 04fb6b838f0..8d47e63eff2 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir @@ -20,11 +20,13 @@ fn demo_byte_add_thin(_1: *const u32, _2: usize) -> *const u32 { } bb0: { + StorageLive(_4); StorageLive(_3); _3 = _1 as *const u8 (PtrToPtr); _4 = Offset(_3, _2); StorageDead(_3); _0 = _4 as *const u32 (PtrToPtr); + StorageDead(_4); return; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index d979c5ec1d5..8f41fb70925 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -4,35 +4,34 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _12: std::slice::Iter<'_, T>; + let mut _11: std::slice::Iter<'_, T>; + let mut _12: std::iter::Enumerate<std::slice::Iter<'_, T>>; let mut _13: std::iter::Enumerate<std::slice::Iter<'_, T>>; - let mut _14: std::iter::Enumerate<std::slice::Iter<'_, T>>; - let mut _15: &mut std::iter::Enumerate<std::slice::Iter<'_, T>>; - let mut _16: std::option::Option<(usize, &T)>; - let mut _17: isize; - let mut _20: &impl Fn(usize, &T); - let mut _21: (usize, &T); - let _22: (); + let mut _14: &mut std::iter::Enumerate<std::slice::Iter<'_, T>>; + let mut _15: std::option::Option<(usize, &T)>; + let mut _16: isize; + let mut _19: &impl Fn(usize, &T); + let mut _20: (usize, &T); + let _21: (); scope 1 { - debug iter => _14; - let _18: usize; - let _19: &T; + debug iter => _13; + let _17: usize; + let _18: &T; scope 2 { - debug i => _18; - debug x => _19; + debug i => _17; + debug x => _18; } } scope 3 (inlined core::slice::<impl [T]>::iter) { scope 4 (inlined std::slice::Iter::<'_, T>::new) { let _3: usize; - let mut _7: bool; + let mut _7: *mut T; let mut _8: *mut T; - let mut _9: *mut T; - let mut _11: *const T; + let mut _10: *const T; scope 5 { let _6: std::ptr::NonNull<T>; scope 6 { - let _10: *const T; + let _9: *const T; scope 7 { } scope 11 (inlined without_provenance::<T>) { @@ -61,7 +60,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb0: { - StorageLive(_12); + StorageLive(_11); StorageLive(_3); StorageLive(_6); StorageLive(_4); @@ -70,62 +69,59 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _4 = &raw const (*_1); _5 = _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: _5 }; - StorageLive(_10); - StorageLive(_7); - _7 = const <T as std::mem::SizedTypeProperties>::IS_ZST; - switchInt(move _7) -> [0: bb1, otherwise: bb2]; + StorageLive(_9); + switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageLive(_9); StorageLive(_8); - _8 = _4 as *mut T (PtrToPtr); - _9 = Offset(_8, _3); + StorageLive(_7); + _7 = _4 as *mut T (PtrToPtr); + _8 = Offset(_7, _3); + StorageDead(_7); + _9 = move _8 as *const T (PointerCoercion(MutToConstPointer)); StorageDead(_8); - _10 = move _9 as *const T (PointerCoercion(MutToConstPointer)); - StorageDead(_9); goto -> bb3; } bb2: { - _10 = _3 as *const T (Transmute); + _9 = _3 as *const T (Transmute); goto -> bb3; } bb3: { - StorageDead(_7); - StorageLive(_11); - _11 = _10; - _12 = std::slice::Iter::<'_, T> { ptr: _6, end_or_len: move _11, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_11); + StorageLive(_10); + _10 = _9; + _11 = std::slice::Iter::<'_, T> { ptr: _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_10); + StorageDead(_9); StorageDead(_5); StorageDead(_4); StorageDead(_6); StorageDead(_3); - _13 = Enumerate::<std::slice::Iter<'_, T>> { iter: _12, count: const 0_usize }; - StorageDead(_12); - StorageLive(_14); - _14 = _13; + _12 = Enumerate::<std::slice::Iter<'_, T>> { iter: _11, count: const 0_usize }; + StorageDead(_11); + StorageLive(_13); + _13 = _12; goto -> bb4; } bb4: { - StorageLive(_16); StorageLive(_15); - _15 = &mut _14; - _16 = <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next(move _15) -> [return: bb5, unwind unreachable]; + StorageLive(_14); + _14 = &mut _13; + _15 = <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next(move _14) -> [return: bb5, unwind unreachable]; } bb5: { - StorageDead(_15); - _17 = discriminant(_16); - switchInt(move _17) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageDead(_14); + _16 = discriminant(_15); + switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10]; } bb6: { - StorageDead(_16); - StorageDead(_14); + StorageDead(_15); + StorageDead(_13); drop(_2) -> [return: bb7, unwind unreachable]; } @@ -134,19 +130,19 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb8: { - _18 = (((_16 as Some).0: (usize, &T)).0: usize); - _19 = (((_16 as Some).0: (usize, &T)).1: &T); + _17 = (((_15 as Some).0: (usize, &T)).0: usize); + _18 = (((_15 as Some).0: (usize, &T)).1: &T); + StorageLive(_19); + _19 = &_2; StorageLive(_20); - _20 = &_2; - StorageLive(_21); - _21 = (_18, _19); - _22 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _20, move _21) -> [return: bb9, unwind unreachable]; + _20 = (_17, _18); + _21 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _19, move _20) -> [return: bb9, unwind unreachable]; } bb9: { - StorageDead(_21); StorageDead(_20); - StorageDead(_16); + StorageDead(_19); + StorageDead(_15); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir index 8491c49f767..17cf305468e 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir @@ -4,35 +4,34 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _12: std::slice::Iter<'_, T>; + let mut _11: std::slice::Iter<'_, T>; + let mut _12: std::iter::Enumerate<std::slice::Iter<'_, T>>; let mut _13: std::iter::Enumerate<std::slice::Iter<'_, T>>; - let mut _14: std::iter::Enumerate<std::slice::Iter<'_, T>>; - let mut _15: &mut std::iter::Enumerate<std::slice::Iter<'_, T>>; - let mut _16: std::option::Option<(usize, &T)>; - let mut _17: isize; - let mut _20: &impl Fn(usize, &T); - let mut _21: (usize, &T); - let _22: (); + let mut _14: &mut std::iter::Enumerate<std::slice::Iter<'_, T>>; + let mut _15: std::option::Option<(usize, &T)>; + let mut _16: isize; + let mut _19: &impl Fn(usize, &T); + let mut _20: (usize, &T); + let _21: (); scope 1 { - debug iter => _14; - let _18: usize; - let _19: &T; + debug iter => _13; + let _17: usize; + let _18: &T; scope 2 { - debug i => _18; - debug x => _19; + debug i => _17; + debug x => _18; } } scope 3 (inlined core::slice::<impl [T]>::iter) { scope 4 (inlined std::slice::Iter::<'_, T>::new) { let _3: usize; - let mut _7: bool; + let mut _7: *mut T; let mut _8: *mut T; - let mut _9: *mut T; - let mut _11: *const T; + let mut _10: *const T; scope 5 { let _6: std::ptr::NonNull<T>; scope 6 { - let _10: *const T; + let _9: *const T; scope 7 { } scope 11 (inlined without_provenance::<T>) { @@ -61,7 +60,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb0: { - StorageLive(_12); + StorageLive(_11); StorageLive(_3); StorageLive(_6); StorageLive(_4); @@ -70,62 +69,59 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _4 = &raw const (*_1); _5 = _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: _5 }; - StorageLive(_10); - StorageLive(_7); - _7 = const <T as std::mem::SizedTypeProperties>::IS_ZST; - switchInt(move _7) -> [0: bb1, otherwise: bb2]; + StorageLive(_9); + switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageLive(_9); StorageLive(_8); - _8 = _4 as *mut T (PtrToPtr); - _9 = Offset(_8, _3); + StorageLive(_7); + _7 = _4 as *mut T (PtrToPtr); + _8 = Offset(_7, _3); + StorageDead(_7); + _9 = move _8 as *const T (PointerCoercion(MutToConstPointer)); StorageDead(_8); - _10 = move _9 as *const T (PointerCoercion(MutToConstPointer)); - StorageDead(_9); goto -> bb3; } bb2: { - _10 = _3 as *const T (Transmute); + _9 = _3 as *const T (Transmute); goto -> bb3; } bb3: { - StorageDead(_7); - StorageLive(_11); - _11 = _10; - _12 = std::slice::Iter::<'_, T> { ptr: _6, end_or_len: move _11, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_11); + StorageLive(_10); + _10 = _9; + _11 = std::slice::Iter::<'_, T> { ptr: _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_10); + StorageDead(_9); StorageDead(_5); StorageDead(_4); StorageDead(_6); StorageDead(_3); - _13 = Enumerate::<std::slice::Iter<'_, T>> { iter: _12, count: const 0_usize }; - StorageDead(_12); - StorageLive(_14); - _14 = _13; + _12 = Enumerate::<std::slice::Iter<'_, T>> { iter: _11, count: const 0_usize }; + StorageDead(_11); + StorageLive(_13); + _13 = _12; goto -> bb4; } bb4: { - StorageLive(_16); StorageLive(_15); - _15 = &mut _14; - _16 = <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next(move _15) -> [return: bb5, unwind: bb11]; + StorageLive(_14); + _14 = &mut _13; + _15 = <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next(move _14) -> [return: bb5, unwind: bb11]; } bb5: { - StorageDead(_15); - _17 = discriminant(_16); - switchInt(move _17) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageDead(_14); + _16 = discriminant(_15); + switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10]; } bb6: { - StorageDead(_16); - StorageDead(_14); + StorageDead(_15); + StorageDead(_13); drop(_2) -> [return: bb7, unwind continue]; } @@ -134,19 +130,19 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb8: { - _18 = (((_16 as Some).0: (usize, &T)).0: usize); - _19 = (((_16 as Some).0: (usize, &T)).1: &T); + _17 = (((_15 as Some).0: (usize, &T)).0: usize); + _18 = (((_15 as Some).0: (usize, &T)).1: &T); + StorageLive(_19); + _19 = &_2; StorageLive(_20); - _20 = &_2; - StorageLive(_21); - _21 = (_18, _19); - _22 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _20, move _21) -> [return: bb9, unwind: bb11]; + _20 = (_17, _18); + _21 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _19, move _20) -> [return: bb9, unwind: bb11]; } bb9: { - StorageDead(_21); StorageDead(_20); - StorageDead(_16); + StorageDead(_19); + StorageDead(_15); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir index 67dd0c85ea1..3c1bbdc8742 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -4,32 +4,31 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); + let mut _11: std::slice::Iter<'_, T>; let mut _12: std::slice::Iter<'_, T>; - let mut _13: std::slice::Iter<'_, T>; - let mut _14: &mut std::slice::Iter<'_, T>; - let mut _15: std::option::Option<&T>; - let mut _16: isize; - let mut _18: &impl Fn(&T); - let mut _19: (&T,); - let _20: (); + let mut _13: &mut std::slice::Iter<'_, T>; + let mut _14: std::option::Option<&T>; + let mut _15: isize; + let mut _17: &impl Fn(&T); + let mut _18: (&T,); + let _19: (); scope 1 { - debug iter => _13; - let _17: &T; + debug iter => _12; + let _16: &T; scope 2 { - debug x => _17; + debug x => _16; } } scope 3 (inlined core::slice::<impl [T]>::iter) { scope 4 (inlined std::slice::Iter::<'_, T>::new) { let _3: usize; - let mut _7: bool; + let mut _7: *mut T; let mut _8: *mut T; - let mut _9: *mut T; - let mut _11: *const T; + let mut _10: *const T; scope 5 { let _6: std::ptr::NonNull<T>; scope 6 { - let _10: *const T; + let _9: *const T; scope 7 { } scope 11 (inlined without_provenance::<T>) { @@ -62,60 +61,57 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { _4 = &raw const (*_1); _5 = _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: _5 }; - StorageLive(_10); - StorageLive(_7); - _7 = const <T as std::mem::SizedTypeProperties>::IS_ZST; - switchInt(move _7) -> [0: bb1, otherwise: bb2]; + StorageLive(_9); + switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageLive(_9); StorageLive(_8); - _8 = _4 as *mut T (PtrToPtr); - _9 = Offset(_8, _3); + StorageLive(_7); + _7 = _4 as *mut T (PtrToPtr); + _8 = Offset(_7, _3); + StorageDead(_7); + _9 = move _8 as *const T (PointerCoercion(MutToConstPointer)); StorageDead(_8); - _10 = move _9 as *const T (PointerCoercion(MutToConstPointer)); - StorageDead(_9); goto -> bb3; } bb2: { - _10 = _3 as *const T (Transmute); + _9 = _3 as *const T (Transmute); goto -> bb3; } bb3: { - StorageDead(_7); - StorageLive(_11); - _11 = _10; - _12 = std::slice::Iter::<'_, T> { ptr: _6, end_or_len: move _11, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_11); + StorageLive(_10); + _10 = _9; + _11 = std::slice::Iter::<'_, T> { ptr: _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_10); + StorageDead(_9); StorageDead(_5); StorageDead(_4); StorageDead(_6); StorageDead(_3); - StorageLive(_13); - _13 = _12; + StorageLive(_12); + _12 = _11; goto -> bb4; } bb4: { - StorageLive(_15); StorageLive(_14); - _14 = &mut _13; - _15 = <std::slice::Iter<'_, T> as Iterator>::next(move _14) -> [return: bb5, unwind unreachable]; + StorageLive(_13); + _13 = &mut _12; + _14 = <std::slice::Iter<'_, T> as Iterator>::next(move _13) -> [return: bb5, unwind unreachable]; } bb5: { - StorageDead(_14); - _16 = discriminant(_15); - switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageDead(_13); + _15 = discriminant(_14); + switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10]; } bb6: { - StorageDead(_15); - StorageDead(_13); + StorageDead(_14); + StorageDead(_12); drop(_2) -> [return: bb7, unwind unreachable]; } @@ -124,18 +120,18 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb8: { - _17 = ((_15 as Some).0: &T); + _16 = ((_14 as Some).0: &T); + StorageLive(_17); + _17 = &_2; StorageLive(_18); - _18 = &_2; - StorageLive(_19); - _19 = (_17,); - _20 = <impl Fn(&T) as Fn<(&T,)>>::call(move _18, move _19) -> [return: bb9, unwind unreachable]; + _18 = (_16,); + _19 = <impl Fn(&T) as Fn<(&T,)>>::call(move _17, move _18) -> [return: bb9, unwind unreachable]; } bb9: { - StorageDead(_19); StorageDead(_18); - StorageDead(_15); + StorageDead(_17); + StorageDead(_14); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir index 7c41e9e1f1b..b2ec1ea7b9f 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -4,32 +4,31 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); + let mut _11: std::slice::Iter<'_, T>; let mut _12: std::slice::Iter<'_, T>; - let mut _13: std::slice::Iter<'_, T>; - let mut _14: &mut std::slice::Iter<'_, T>; - let mut _15: std::option::Option<&T>; - let mut _16: isize; - let mut _18: &impl Fn(&T); - let mut _19: (&T,); - let _20: (); + let mut _13: &mut std::slice::Iter<'_, T>; + let mut _14: std::option::Option<&T>; + let mut _15: isize; + let mut _17: &impl Fn(&T); + let mut _18: (&T,); + let _19: (); scope 1 { - debug iter => _13; - let _17: &T; + debug iter => _12; + let _16: &T; scope 2 { - debug x => _17; + debug x => _16; } } scope 3 (inlined core::slice::<impl [T]>::iter) { scope 4 (inlined std::slice::Iter::<'_, T>::new) { let _3: usize; - let mut _7: bool; + let mut _7: *mut T; let mut _8: *mut T; - let mut _9: *mut T; - let mut _11: *const T; + let mut _10: *const T; scope 5 { let _6: std::ptr::NonNull<T>; scope 6 { - let _10: *const T; + let _9: *const T; scope 7 { } scope 11 (inlined without_provenance::<T>) { @@ -62,60 +61,57 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { _4 = &raw const (*_1); _5 = _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: _5 }; - StorageLive(_10); - StorageLive(_7); - _7 = const <T as std::mem::SizedTypeProperties>::IS_ZST; - switchInt(move _7) -> [0: bb1, otherwise: bb2]; + StorageLive(_9); + switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageLive(_9); StorageLive(_8); - _8 = _4 as *mut T (PtrToPtr); - _9 = Offset(_8, _3); + StorageLive(_7); + _7 = _4 as *mut T (PtrToPtr); + _8 = Offset(_7, _3); + StorageDead(_7); + _9 = move _8 as *const T (PointerCoercion(MutToConstPointer)); StorageDead(_8); - _10 = move _9 as *const T (PointerCoercion(MutToConstPointer)); - StorageDead(_9); goto -> bb3; } bb2: { - _10 = _3 as *const T (Transmute); + _9 = _3 as *const T (Transmute); goto -> bb3; } bb3: { - StorageDead(_7); - StorageLive(_11); - _11 = _10; - _12 = std::slice::Iter::<'_, T> { ptr: _6, end_or_len: move _11, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_11); + StorageLive(_10); + _10 = _9; + _11 = std::slice::Iter::<'_, T> { ptr: _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_10); + StorageDead(_9); StorageDead(_5); StorageDead(_4); StorageDead(_6); StorageDead(_3); - StorageLive(_13); - _13 = _12; + StorageLive(_12); + _12 = _11; goto -> bb4; } bb4: { - StorageLive(_15); StorageLive(_14); - _14 = &mut _13; - _15 = <std::slice::Iter<'_, T> as Iterator>::next(move _14) -> [return: bb5, unwind: bb11]; + StorageLive(_13); + _13 = &mut _12; + _14 = <std::slice::Iter<'_, T> as Iterator>::next(move _13) -> [return: bb5, unwind: bb11]; } bb5: { - StorageDead(_14); - _16 = discriminant(_15); - switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageDead(_13); + _15 = discriminant(_14); + switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10]; } bb6: { - StorageDead(_15); - StorageDead(_13); + StorageDead(_14); + StorageDead(_12); drop(_2) -> [return: bb7, unwind continue]; } @@ -124,18 +120,18 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb8: { - _17 = ((_15 as Some).0: &T); + _16 = ((_14 as Some).0: &T); + StorageLive(_17); + _17 = &_2; StorageLive(_18); - _18 = &_2; - StorageLive(_19); - _19 = (_17,); - _20 = <impl Fn(&T) as Fn<(&T,)>>::call(move _18, move _19) -> [return: bb9, unwind: bb11]; + _18 = (_16,); + _19 = <impl Fn(&T) as Fn<(&T,)>>::call(move _17, move _18) -> [return: bb9, unwind: bb11]; } bb9: { - StorageDead(_19); StorageDead(_18); - StorageDead(_15); + StorageDead(_17); + StorageDead(_14); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir index ffeef1e04a1..bf982f076de 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir @@ -4,35 +4,34 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _12: std::slice::Iter<'_, T>; + let mut _11: std::slice::Iter<'_, T>; + let mut _12: std::iter::Rev<std::slice::Iter<'_, T>>; let mut _13: std::iter::Rev<std::slice::Iter<'_, T>>; - let mut _14: std::iter::Rev<std::slice::Iter<'_, T>>; - let mut _16: std::option::Option<&T>; - let mut _17: isize; - let mut _19: &impl Fn(&T); - let mut _20: (&T,); - let _21: (); + let mut _15: std::option::Option<&T>; + let mut _16: isize; + let mut _18: &impl Fn(&T); + let mut _19: (&T,); + let _20: (); scope 1 { - debug iter => _14; - let _18: &T; + debug iter => _13; + let _17: &T; scope 2 { - debug x => _18; + debug x => _17; } scope 17 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) { - let mut _15: &mut std::slice::Iter<'_, T>; + let mut _14: &mut std::slice::Iter<'_, T>; } } scope 3 (inlined core::slice::<impl [T]>::iter) { scope 4 (inlined std::slice::Iter::<'_, T>::new) { let _3: usize; - let mut _7: bool; + let mut _7: *mut T; let mut _8: *mut T; - let mut _9: *mut T; - let mut _11: *const T; + let mut _10: *const T; scope 5 { let _6: std::ptr::NonNull<T>; scope 6 { - let _10: *const T; + let _9: *const T; scope 7 { } scope 11 (inlined without_provenance::<T>) { @@ -61,7 +60,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb0: { - StorageLive(_12); + StorageLive(_11); StorageLive(_3); StorageLive(_6); StorageLive(_4); @@ -70,62 +69,59 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _4 = &raw const (*_1); _5 = _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: _5 }; - StorageLive(_10); - StorageLive(_7); - _7 = const <T as std::mem::SizedTypeProperties>::IS_ZST; - switchInt(move _7) -> [0: bb1, otherwise: bb2]; + StorageLive(_9); + switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageLive(_9); StorageLive(_8); - _8 = _4 as *mut T (PtrToPtr); - _9 = Offset(_8, _3); + StorageLive(_7); + _7 = _4 as *mut T (PtrToPtr); + _8 = Offset(_7, _3); + StorageDead(_7); + _9 = move _8 as *const T (PointerCoercion(MutToConstPointer)); StorageDead(_8); - _10 = move _9 as *const T (PointerCoercion(MutToConstPointer)); - StorageDead(_9); goto -> bb3; } bb2: { - _10 = _3 as *const T (Transmute); + _9 = _3 as *const T (Transmute); goto -> bb3; } bb3: { - StorageDead(_7); - StorageLive(_11); - _11 = _10; - _12 = std::slice::Iter::<'_, T> { ptr: _6, end_or_len: move _11, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_11); + StorageLive(_10); + _10 = _9; + _11 = std::slice::Iter::<'_, T> { ptr: _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_10); + StorageDead(_9); StorageDead(_5); StorageDead(_4); StorageDead(_6); StorageDead(_3); - _13 = Rev::<std::slice::Iter<'_, T>> { iter: _12 }; - StorageDead(_12); - StorageLive(_14); - _14 = _13; + _12 = Rev::<std::slice::Iter<'_, T>> { iter: _11 }; + StorageDead(_11); + StorageLive(_13); + _13 = _12; goto -> bb4; } bb4: { - StorageLive(_16); StorageLive(_15); - _15 = &mut (_14.0: std::slice::Iter<'_, T>); - _16 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _15) -> [return: bb5, unwind unreachable]; + StorageLive(_14); + _14 = &mut (_13.0: std::slice::Iter<'_, T>); + _15 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _14) -> [return: bb5, unwind unreachable]; } bb5: { - StorageDead(_15); - _17 = discriminant(_16); - switchInt(move _17) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageDead(_14); + _16 = discriminant(_15); + switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10]; } bb6: { - StorageDead(_16); - StorageDead(_14); + StorageDead(_15); + StorageDead(_13); drop(_2) -> [return: bb7, unwind unreachable]; } @@ -134,18 +130,18 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb8: { - _18 = ((_16 as Some).0: &T); + _17 = ((_15 as Some).0: &T); + StorageLive(_18); + _18 = &_2; StorageLive(_19); - _19 = &_2; - StorageLive(_20); - _20 = (_18,); - _21 = <impl Fn(&T) as Fn<(&T,)>>::call(move _19, move _20) -> [return: bb9, unwind unreachable]; + _19 = (_17,); + _20 = <impl Fn(&T) as Fn<(&T,)>>::call(move _18, move _19) -> [return: bb9, unwind unreachable]; } bb9: { - StorageDead(_20); StorageDead(_19); - StorageDead(_16); + StorageDead(_18); + StorageDead(_15); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir index c7cd37afd86..532b8162521 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir @@ -4,35 +4,34 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _12: std::slice::Iter<'_, T>; + let mut _11: std::slice::Iter<'_, T>; + let mut _12: std::iter::Rev<std::slice::Iter<'_, T>>; let mut _13: std::iter::Rev<std::slice::Iter<'_, T>>; - let mut _14: std::iter::Rev<std::slice::Iter<'_, T>>; - let mut _16: std::option::Option<&T>; - let mut _17: isize; - let mut _19: &impl Fn(&T); - let mut _20: (&T,); - let _21: (); + let mut _15: std::option::Option<&T>; + let mut _16: isize; + let mut _18: &impl Fn(&T); + let mut _19: (&T,); + let _20: (); scope 1 { - debug iter => _14; - let _18: &T; + debug iter => _13; + let _17: &T; scope 2 { - debug x => _18; + debug x => _17; } scope 17 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) { - let mut _15: &mut std::slice::Iter<'_, T>; + let mut _14: &mut std::slice::Iter<'_, T>; } } scope 3 (inlined core::slice::<impl [T]>::iter) { scope 4 (inlined std::slice::Iter::<'_, T>::new) { let _3: usize; - let mut _7: bool; + let mut _7: *mut T; let mut _8: *mut T; - let mut _9: *mut T; - let mut _11: *const T; + let mut _10: *const T; scope 5 { let _6: std::ptr::NonNull<T>; scope 6 { - let _10: *const T; + let _9: *const T; scope 7 { } scope 11 (inlined without_provenance::<T>) { @@ -61,7 +60,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb0: { - StorageLive(_12); + StorageLive(_11); StorageLive(_3); StorageLive(_6); StorageLive(_4); @@ -70,62 +69,59 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _4 = &raw const (*_1); _5 = _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: _5 }; - StorageLive(_10); - StorageLive(_7); - _7 = const <T as std::mem::SizedTypeProperties>::IS_ZST; - switchInt(move _7) -> [0: bb1, otherwise: bb2]; + StorageLive(_9); + switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageLive(_9); StorageLive(_8); - _8 = _4 as *mut T (PtrToPtr); - _9 = Offset(_8, _3); + StorageLive(_7); + _7 = _4 as *mut T (PtrToPtr); + _8 = Offset(_7, _3); + StorageDead(_7); + _9 = move _8 as *const T (PointerCoercion(MutToConstPointer)); StorageDead(_8); - _10 = move _9 as *const T (PointerCoercion(MutToConstPointer)); - StorageDead(_9); goto -> bb3; } bb2: { - _10 = _3 as *const T (Transmute); + _9 = _3 as *const T (Transmute); goto -> bb3; } bb3: { - StorageDead(_7); - StorageLive(_11); - _11 = _10; - _12 = std::slice::Iter::<'_, T> { ptr: _6, end_or_len: move _11, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_11); + StorageLive(_10); + _10 = _9; + _11 = std::slice::Iter::<'_, T> { ptr: _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_10); + StorageDead(_9); StorageDead(_5); StorageDead(_4); StorageDead(_6); StorageDead(_3); - _13 = Rev::<std::slice::Iter<'_, T>> { iter: _12 }; - StorageDead(_12); - StorageLive(_14); - _14 = _13; + _12 = Rev::<std::slice::Iter<'_, T>> { iter: _11 }; + StorageDead(_11); + StorageLive(_13); + _13 = _12; goto -> bb4; } bb4: { - StorageLive(_16); StorageLive(_15); - _15 = &mut (_14.0: std::slice::Iter<'_, T>); - _16 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _15) -> [return: bb5, unwind: bb11]; + StorageLive(_14); + _14 = &mut (_13.0: std::slice::Iter<'_, T>); + _15 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _14) -> [return: bb5, unwind: bb11]; } bb5: { - StorageDead(_15); - _17 = discriminant(_16); - switchInt(move _17) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageDead(_14); + _16 = discriminant(_15); + switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10]; } bb6: { - StorageDead(_16); - StorageDead(_14); + StorageDead(_15); + StorageDead(_13); drop(_2) -> [return: bb7, unwind continue]; } @@ -134,18 +130,18 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb8: { - _18 = ((_16 as Some).0: &T); + _17 = ((_15 as Some).0: &T); + StorageLive(_18); + _18 = &_2; StorageLive(_19); - _19 = &_2; - StorageLive(_20); - _20 = (_18,); - _21 = <impl Fn(&T) as Fn<(&T,)>>::call(move _19, move _20) -> [return: bb9, unwind: bb11]; + _19 = (_17,); + _20 = <impl Fn(&T) as Fn<(&T,)>>::call(move _18, move _19) -> [return: bb9, unwind: bb11]; } bb9: { - StorageDead(_20); StorageDead(_19); - StorageDead(_16); + StorageDead(_18); + StorageDead(_15); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/try_identity.rs b/tests/mir-opt/pre-codegen/try_identity.rs index 2e17a3ae6e7..264b303e381 100644 --- a/tests/mir-opt/pre-codegen/try_identity.rs +++ b/tests/mir-opt/pre-codegen/try_identity.rs @@ -17,18 +17,16 @@ fn new<T, E>(x: Result<T, E>) -> Result<T, E> { } { ControlFlow::Continue(v) => v, ControlFlow::Break(e) => return Err(e), - } + }, ) } // EMIT_MIR try_identity.old.PreCodegen.after.mir fn old<T, E>(x: Result<T, E>) -> Result<T, E> { - Ok( - match x { - Ok(v) => v, - Err(e) => return Err(e), - } - ) + Ok(match x { + Ok(v) => v, + Err(e) => return Err(e), + }) } fn main() { diff --git a/tests/mir-opt/reference_prop.rs b/tests/mir-opt/reference_prop.rs index e0b0d699420..58d8b524ad6 100644 --- a/tests/mir-opt/reference_prop.rs +++ b/tests/mir-opt/reference_prop.rs @@ -658,7 +658,7 @@ fn read_through_raw(x: &mut usize) -> usize { // CHECK-NEXT: return; use std::intrinsics::mir::*; - mir!( + mir! { let r1: &mut usize; let r2: &mut usize; let p1: *mut usize; @@ -674,7 +674,7 @@ fn read_through_raw(x: &mut usize) -> usize { RET = *p2; Return() } - ) + } } #[custom_mir(dialect = "runtime", phase = "post-cleanup")] @@ -683,7 +683,7 @@ fn multiple_storage() { // CHECK: _3 = (*_2); use std::intrinsics::mir::*; - mir!( + mir! { let x: i32; { StorageLive(x); @@ -700,7 +700,7 @@ fn multiple_storage() { retblock = { Return() } - ) + } } #[custom_mir(dialect = "runtime", phase = "post-cleanup")] @@ -709,7 +709,7 @@ fn dominate_storage() { // CHECK: _5 = (*_2); use std::intrinsics::mir::*; - mir!( + mir! { let x: i32; let r: &i32; let c: i32; @@ -730,7 +730,7 @@ fn dominate_storage() { let d = true; match d { false => bb2, _ => bb0 } } - ) + } } #[custom_mir(dialect = "runtime", phase = "post-cleanup")] @@ -739,7 +739,7 @@ fn maybe_dead(m: bool) { // CHECK: (*_5) = const 7_i32; use std::intrinsics::mir::*; - mir!( + mir! { let x: i32; let y: i32; { @@ -774,7 +774,7 @@ fn maybe_dead(m: bool) { retblock = { Return() } - ) + } } fn mut_raw_then_mut_shr() -> (i32, i32) { @@ -787,7 +787,9 @@ fn mut_raw_then_mut_shr() -> (i32, i32) { let xshr = &*xref; // Verify that we completely replace with `x` in both cases. let a = *xshr; - unsafe { *xraw = 4; } + unsafe { + *xraw = 4; + } (a, x) } @@ -842,8 +844,7 @@ fn debuginfo() { // `constant_index_from_end` and `subslice` should not be promoted, as their value depends // on the slice length. - if let [_, ref constant_index, subslice @ .., ref constant_index_from_end] = &[6; 10][..] { - } + if let [_, ref constant_index, subslice @ .., ref constant_index_from_end] = &[6; 10][..] {} let multiple_borrow = &&&mut T(6).0; } diff --git a/tests/mir-opt/retag.rs b/tests/mir-opt/retag.rs index 43d74aa5726..001c5599138 100644 --- a/tests/mir-opt/retag.rs +++ b/tests/mir-opt/retag.rs @@ -59,7 +59,9 @@ pub fn main() { fn array_casts() { let mut x: [usize; 2] = [0, 0]; let p = &mut x as *mut usize; - unsafe { *p.add(1) = 1; } + unsafe { + *p.add(1) = 1; + } let x: [usize; 2] = [0, 1]; let p = &x as *const usize; diff --git a/tests/mir-opt/return_an_array.rs b/tests/mir-opt/return_an_array.rs index 09146a824fc..673b5df7d73 100644 --- a/tests/mir-opt/return_an_array.rs +++ b/tests/mir-opt/return_an_array.rs @@ -2,8 +2,8 @@ // this tests move up progration, which is not yet implemented fn foo() -> [u8; 1024] { - let x = [0; 1024]; - return x; + let x = [0; 1024]; + return x; } -fn main() { } +fn main() {} diff --git a/tests/mir-opt/set_no_discriminant.rs b/tests/mir-opt/set_no_discriminant.rs index 0c29d1faf02..586e28ae426 100644 --- a/tests/mir-opt/set_no_discriminant.rs +++ b/tests/mir-opt/set_no_discriminant.rs @@ -19,7 +19,7 @@ pub fn f() -> usize { // CHECK-NOT: goto // CHECK: switchInt( // CHECK-NOT: goto - mir!( + mir! { let a: isize; let e: E<char>; { @@ -39,7 +39,7 @@ pub fn f() -> usize { RET = 1; Return() } - ) + } } // EMIT_MIR set_no_discriminant.generic.JumpThreading.diff @@ -49,7 +49,7 @@ pub fn generic<T>() -> usize { // CHECK-NOT: goto // CHECK: switchInt( // CHECK-NOT: goto - mir!( + mir! { let a: isize; let e: E<T>; { @@ -69,7 +69,7 @@ pub fn generic<T>() -> usize { RET = 1; Return() } - ) + } } fn main() { diff --git a/tests/mir-opt/simplify_dead_blocks.rs b/tests/mir-opt/simplify_dead_blocks.rs index 686eac58236..b9a404fd35c 100644 --- a/tests/mir-opt/simplify_dead_blocks.rs +++ b/tests/mir-opt/simplify_dead_blocks.rs @@ -24,7 +24,7 @@ pub unsafe fn assert_nonzero_nonmax(x: u8) -> u8 { // CHECK-NEXT: _0 = _1; // CHECK-NEXT: return; // CHECK-NEXT: } - mir!( + mir! { { match x { 0 => unreachable, @@ -48,5 +48,5 @@ pub unsafe fn assert_nonzero_nonmax(x: u8) -> u8 { RET = x; Return() } - ) + } } diff --git a/tests/mir-opt/simplify_locals.rs b/tests/mir-opt/simplify_locals.rs index f57611111cf..6511b5e87e4 100644 --- a/tests/mir-opt/simplify_locals.rs +++ b/tests/mir-opt/simplify_locals.rs @@ -1,13 +1,12 @@ // skip-filecheck //@ test-mir-pass: SimplifyLocals-before-const-prop - #![feature(thread_local)] #[derive(Copy, Clone)] enum E { - A, - B, + A, + B, } // EMIT_MIR simplify_locals.c.SimplifyLocals-before-const-prop.diff @@ -26,7 +25,7 @@ fn d1() { // EMIT_MIR simplify_locals.d2.SimplifyLocals-before-const-prop.diff fn d2() { // Unused set discriminant - {(10, E::A)}.1 = E::B; + { (10, E::A) }.1 = E::B; } // EMIT_MIR simplify_locals.r.SimplifyLocals-before-const-prop.diff @@ -37,7 +36,8 @@ fn r() { let _ = &mut a; } -#[thread_local] static mut X: u32 = 0; +#[thread_local] +static mut X: u32 = 0; // EMIT_MIR simplify_locals.t1.SimplifyLocals-before-const-prop.diff fn t1() { diff --git a/tests/mir-opt/simplify_locals_fixedpoint.rs b/tests/mir-opt/simplify_locals_fixedpoint.rs index 6947d31dc3e..0b6c95630c0 100644 --- a/tests/mir-opt/simplify_locals_fixedpoint.rs +++ b/tests/mir-opt/simplify_locals_fixedpoint.rs @@ -4,9 +4,7 @@ fn foo<T>() { if let (Some(a), None) = (Option::<u8>::None, Option::<T>::None) { - if a > 42u8 { - - } + if a > 42u8 {} } } diff --git a/tests/mir-opt/simplify_match.rs b/tests/mir-opt/simplify_match.rs index 2eac93edbb8..b035b6339fa 100644 --- a/tests/mir-opt/simplify_match.rs +++ b/tests/mir-opt/simplify_match.rs @@ -5,8 +5,11 @@ fn noop() {} // EMIT_MIR simplify_match.main.GVN.diff fn main() { - match { let x = false; x } { + match { + let x = false; + x + } { true => noop(), - false => {}, + false => {} } } diff --git a/tests/mir-opt/single_use_consts.assign_const_to_return.SingleUseConsts.panic-abort.diff b/tests/mir-opt/single_use_consts.assign_const_to_return.SingleUseConsts.panic-abort.diff new file mode 100644 index 00000000000..8818c891e94 --- /dev/null +++ b/tests/mir-opt/single_use_consts.assign_const_to_return.SingleUseConsts.panic-abort.diff @@ -0,0 +1,12 @@ +- // MIR for `assign_const_to_return` before SingleUseConsts ++ // MIR for `assign_const_to_return` after SingleUseConsts + + fn assign_const_to_return() -> bool { + let mut _0: bool; + + bb0: { + _0 = const <T as MyTrait>::ASSOC_BOOL; + return; + } + } + diff --git a/tests/mir-opt/single_use_consts.assign_const_to_return.SingleUseConsts.panic-unwind.diff b/tests/mir-opt/single_use_consts.assign_const_to_return.SingleUseConsts.panic-unwind.diff new file mode 100644 index 00000000000..8818c891e94 --- /dev/null +++ b/tests/mir-opt/single_use_consts.assign_const_to_return.SingleUseConsts.panic-unwind.diff @@ -0,0 +1,12 @@ +- // MIR for `assign_const_to_return` before SingleUseConsts ++ // MIR for `assign_const_to_return` after SingleUseConsts + + fn assign_const_to_return() -> bool { + let mut _0: bool; + + bb0: { + _0 = const <T as MyTrait>::ASSOC_BOOL; + return; + } + } + diff --git a/tests/mir-opt/single_use_consts.if_const.SingleUseConsts.panic-abort.diff b/tests/mir-opt/single_use_consts.if_const.SingleUseConsts.panic-abort.diff new file mode 100644 index 00000000000..468076e5ee3 --- /dev/null +++ b/tests/mir-opt/single_use_consts.if_const.SingleUseConsts.panic-abort.diff @@ -0,0 +1,31 @@ +- // MIR for `if_const` before SingleUseConsts ++ // MIR for `if_const` after SingleUseConsts + + fn if_const() -> i32 { + let mut _0: i32; + let mut _1: bool; + + bb0: { + StorageLive(_1); +- _1 = const <T as MyTrait>::ASSOC_BOOL; +- switchInt(move _1) -> [0: bb2, otherwise: bb1]; ++ nop; ++ switchInt(const <T as MyTrait>::ASSOC_BOOL) -> [0: bb2, otherwise: bb1]; + } + + bb1: { + _0 = const 7_i32; + goto -> bb3; + } + + bb2: { + _0 = const 42_i32; + goto -> bb3; + } + + bb3: { + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/single_use_consts.if_const.SingleUseConsts.panic-unwind.diff b/tests/mir-opt/single_use_consts.if_const.SingleUseConsts.panic-unwind.diff new file mode 100644 index 00000000000..468076e5ee3 --- /dev/null +++ b/tests/mir-opt/single_use_consts.if_const.SingleUseConsts.panic-unwind.diff @@ -0,0 +1,31 @@ +- // MIR for `if_const` before SingleUseConsts ++ // MIR for `if_const` after SingleUseConsts + + fn if_const() -> i32 { + let mut _0: i32; + let mut _1: bool; + + bb0: { + StorageLive(_1); +- _1 = const <T as MyTrait>::ASSOC_BOOL; +- switchInt(move _1) -> [0: bb2, otherwise: bb1]; ++ nop; ++ switchInt(const <T as MyTrait>::ASSOC_BOOL) -> [0: bb2, otherwise: bb1]; + } + + bb1: { + _0 = const 7_i32; + goto -> bb3; + } + + bb2: { + _0 = const 42_i32; + goto -> bb3; + } + + bb3: { + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/single_use_consts.if_const_debug.SingleUseConsts.panic-abort.diff b/tests/mir-opt/single_use_consts.if_const_debug.SingleUseConsts.panic-abort.diff new file mode 100644 index 00000000000..ad1a2b300f2 --- /dev/null +++ b/tests/mir-opt/single_use_consts.if_const_debug.SingleUseConsts.panic-abort.diff @@ -0,0 +1,46 @@ +- // MIR for `if_const_debug` before SingleUseConsts ++ // MIR for `if_const_debug` after SingleUseConsts + + fn if_const_debug() -> i32 { + let mut _0: i32; + let _1: bool; + let _2: (); + let mut _3: bool; + scope 1 { +- debug my_bool => _1; ++ debug my_bool => const <T as MyTrait>::ASSOC_BOOL; + } + + bb0: { + StorageLive(_1); +- _1 = const <T as MyTrait>::ASSOC_BOOL; ++ nop; + StorageLive(_2); + _2 = do_whatever() -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); +- _3 = _1; ++ _3 = const <T as MyTrait>::ASSOC_BOOL; + switchInt(move _3) -> [0: bb3, otherwise: bb2]; + } + + bb2: { + _0 = const 7_i32; + goto -> bb4; + } + + bb3: { + _0 = const 42_i32; + goto -> bb4; + } + + bb4: { + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/single_use_consts.if_const_debug.SingleUseConsts.panic-unwind.diff b/tests/mir-opt/single_use_consts.if_const_debug.SingleUseConsts.panic-unwind.diff new file mode 100644 index 00000000000..827a292e5d0 --- /dev/null +++ b/tests/mir-opt/single_use_consts.if_const_debug.SingleUseConsts.panic-unwind.diff @@ -0,0 +1,46 @@ +- // MIR for `if_const_debug` before SingleUseConsts ++ // MIR for `if_const_debug` after SingleUseConsts + + fn if_const_debug() -> i32 { + let mut _0: i32; + let _1: bool; + let _2: (); + let mut _3: bool; + scope 1 { +- debug my_bool => _1; ++ debug my_bool => const <T as MyTrait>::ASSOC_BOOL; + } + + bb0: { + StorageLive(_1); +- _1 = const <T as MyTrait>::ASSOC_BOOL; ++ nop; + StorageLive(_2); + _2 = do_whatever() -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_2); + StorageLive(_3); +- _3 = _1; ++ _3 = const <T as MyTrait>::ASSOC_BOOL; + switchInt(move _3) -> [0: bb3, otherwise: bb2]; + } + + bb2: { + _0 = const 7_i32; + goto -> bb4; + } + + bb3: { + _0 = const 42_i32; + goto -> bb4; + } + + bb4: { + StorageDead(_3); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/single_use_consts.keep_parameter.SingleUseConsts.panic-abort.diff b/tests/mir-opt/single_use_consts.keep_parameter.SingleUseConsts.panic-abort.diff new file mode 100644 index 00000000000..f7d823af9e3 --- /dev/null +++ b/tests/mir-opt/single_use_consts.keep_parameter.SingleUseConsts.panic-abort.diff @@ -0,0 +1,14 @@ +- // MIR for `keep_parameter` before SingleUseConsts ++ // MIR for `keep_parameter` after SingleUseConsts + + fn keep_parameter(_1: i32) -> () { + debug other => _1; + let mut _0: (); + + bb0: { + _1 = const <T as MyTrait>::ASSOC_INT; + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/single_use_consts.keep_parameter.SingleUseConsts.panic-unwind.diff b/tests/mir-opt/single_use_consts.keep_parameter.SingleUseConsts.panic-unwind.diff new file mode 100644 index 00000000000..f7d823af9e3 --- /dev/null +++ b/tests/mir-opt/single_use_consts.keep_parameter.SingleUseConsts.panic-unwind.diff @@ -0,0 +1,14 @@ +- // MIR for `keep_parameter` before SingleUseConsts ++ // MIR for `keep_parameter` after SingleUseConsts + + fn keep_parameter(_1: i32) -> () { + debug other => _1; + let mut _0: (); + + bb0: { + _1 = const <T as MyTrait>::ASSOC_INT; + _0 = const (); + return; + } + } + diff --git a/tests/mir-opt/single_use_consts.match_const.SingleUseConsts.panic-abort.diff b/tests/mir-opt/single_use_consts.match_const.SingleUseConsts.panic-abort.diff new file mode 100644 index 00000000000..8d87438a47a --- /dev/null +++ b/tests/mir-opt/single_use_consts.match_const.SingleUseConsts.panic-abort.diff @@ -0,0 +1,36 @@ +- // MIR for `match_const` before SingleUseConsts ++ // MIR for `match_const` after SingleUseConsts + + fn match_const() -> &str { + let mut _0: &str; + let mut _1: i32; + + bb0: { + StorageLive(_1); +- _1 = const <T as MyTrait>::ASSOC_INT; +- switchInt(_1) -> [7: bb2, 42: bb3, otherwise: bb1]; ++ nop; ++ switchInt(const <T as MyTrait>::ASSOC_INT) -> [7: bb2, 42: bb3, otherwise: bb1]; + } + + bb1: { + _0 = const "world"; + goto -> bb4; + } + + bb2: { + _0 = const "hello"; + goto -> bb4; + } + + bb3: { + _0 = const "towel"; + goto -> bb4; + } + + bb4: { + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/single_use_consts.match_const.SingleUseConsts.panic-unwind.diff b/tests/mir-opt/single_use_consts.match_const.SingleUseConsts.panic-unwind.diff new file mode 100644 index 00000000000..8d87438a47a --- /dev/null +++ b/tests/mir-opt/single_use_consts.match_const.SingleUseConsts.panic-unwind.diff @@ -0,0 +1,36 @@ +- // MIR for `match_const` before SingleUseConsts ++ // MIR for `match_const` after SingleUseConsts + + fn match_const() -> &str { + let mut _0: &str; + let mut _1: i32; + + bb0: { + StorageLive(_1); +- _1 = const <T as MyTrait>::ASSOC_INT; +- switchInt(_1) -> [7: bb2, 42: bb3, otherwise: bb1]; ++ nop; ++ switchInt(const <T as MyTrait>::ASSOC_INT) -> [7: bb2, 42: bb3, otherwise: bb1]; + } + + bb1: { + _0 = const "world"; + goto -> bb4; + } + + bb2: { + _0 = const "hello"; + goto -> bb4; + } + + bb3: { + _0 = const "towel"; + goto -> bb4; + } + + bb4: { + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/single_use_consts.match_const_debug.SingleUseConsts.panic-abort.diff b/tests/mir-opt/single_use_consts.match_const_debug.SingleUseConsts.panic-abort.diff new file mode 100644 index 00000000000..f192f3feb96 --- /dev/null +++ b/tests/mir-opt/single_use_consts.match_const_debug.SingleUseConsts.panic-abort.diff @@ -0,0 +1,47 @@ +- // MIR for `match_const_debug` before SingleUseConsts ++ // MIR for `match_const_debug` after SingleUseConsts + + fn match_const_debug() -> &str { + let mut _0: &str; + let _1: i32; + let _2: (); + scope 1 { +- debug my_int => _1; ++ debug my_int => const <T as MyTrait>::ASSOC_INT; + } + + bb0: { + StorageLive(_1); +- _1 = const <T as MyTrait>::ASSOC_INT; ++ nop; + StorageLive(_2); + _2 = do_whatever() -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_2); +- switchInt(_1) -> [7: bb3, 42: bb4, otherwise: bb2]; ++ switchInt(const <T as MyTrait>::ASSOC_INT) -> [7: bb3, 42: bb4, otherwise: bb2]; + } + + bb2: { + _0 = const "world"; + goto -> bb5; + } + + bb3: { + _0 = const "hello"; + goto -> bb5; + } + + bb4: { + _0 = const "towel"; + goto -> bb5; + } + + bb5: { + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/single_use_consts.match_const_debug.SingleUseConsts.panic-unwind.diff b/tests/mir-opt/single_use_consts.match_const_debug.SingleUseConsts.panic-unwind.diff new file mode 100644 index 00000000000..261faf415f3 --- /dev/null +++ b/tests/mir-opt/single_use_consts.match_const_debug.SingleUseConsts.panic-unwind.diff @@ -0,0 +1,47 @@ +- // MIR for `match_const_debug` before SingleUseConsts ++ // MIR for `match_const_debug` after SingleUseConsts + + fn match_const_debug() -> &str { + let mut _0: &str; + let _1: i32; + let _2: (); + scope 1 { +- debug my_int => _1; ++ debug my_int => const <T as MyTrait>::ASSOC_INT; + } + + bb0: { + StorageLive(_1); +- _1 = const <T as MyTrait>::ASSOC_INT; ++ nop; + StorageLive(_2); + _2 = do_whatever() -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_2); +- switchInt(_1) -> [7: bb3, 42: bb4, otherwise: bb2]; ++ switchInt(const <T as MyTrait>::ASSOC_INT) -> [7: bb3, 42: bb4, otherwise: bb2]; + } + + bb2: { + _0 = const "world"; + goto -> bb5; + } + + bb3: { + _0 = const "hello"; + goto -> bb5; + } + + bb4: { + _0 = const "towel"; + goto -> bb5; + } + + bb5: { + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/single_use_consts.never_used_debug.SingleUseConsts.panic-abort.diff b/tests/mir-opt/single_use_consts.never_used_debug.SingleUseConsts.panic-abort.diff new file mode 100644 index 00000000000..8ef94a790a3 --- /dev/null +++ b/tests/mir-opt/single_use_consts.never_used_debug.SingleUseConsts.panic-abort.diff @@ -0,0 +1,21 @@ +- // MIR for `never_used_debug` before SingleUseConsts ++ // MIR for `never_used_debug` after SingleUseConsts + + fn never_used_debug() -> () { + let mut _0: (); + let _1: i32; + scope 1 { +- debug my_int => _1; ++ debug my_int => const <T as MyTrait>::ASSOC_INT; + } + + bb0: { + StorageLive(_1); +- _1 = const <T as MyTrait>::ASSOC_INT; ++ nop; + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/single_use_consts.never_used_debug.SingleUseConsts.panic-unwind.diff b/tests/mir-opt/single_use_consts.never_used_debug.SingleUseConsts.panic-unwind.diff new file mode 100644 index 00000000000..8ef94a790a3 --- /dev/null +++ b/tests/mir-opt/single_use_consts.never_used_debug.SingleUseConsts.panic-unwind.diff @@ -0,0 +1,21 @@ +- // MIR for `never_used_debug` before SingleUseConsts ++ // MIR for `never_used_debug` after SingleUseConsts + + fn never_used_debug() -> () { + let mut _0: (); + let _1: i32; + scope 1 { +- debug my_int => _1; ++ debug my_int => const <T as MyTrait>::ASSOC_INT; + } + + bb0: { + StorageLive(_1); +- _1 = const <T as MyTrait>::ASSOC_INT; ++ nop; + _0 = const (); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/single_use_consts.rs b/tests/mir-opt/single_use_consts.rs new file mode 100644 index 00000000000..ecb602c647a --- /dev/null +++ b/tests/mir-opt/single_use_consts.rs @@ -0,0 +1,80 @@ +//@ test-mir-pass: SingleUseConsts +//@ compile-flags: -C debuginfo=full +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY + +trait MyTrait { + const ASSOC_BOOL: bool; + const ASSOC_INT: i32; +} + +// EMIT_MIR single_use_consts.if_const.SingleUseConsts.diff +fn if_const<T: MyTrait>() -> i32 { + // CHECK-LABEL: fn if_const( + // CHECK: switchInt(const <T as MyTrait>::ASSOC_BOOL) + if T::ASSOC_BOOL { 7 } else { 42 } +} + +// EMIT_MIR single_use_consts.match_const.SingleUseConsts.diff +fn match_const<T: MyTrait>() -> &'static str { + // CHECK-LABEL: fn match_const( + // CHECK: switchInt(const <T as MyTrait>::ASSOC_INT) + match T::ASSOC_INT { + 7 => "hello", + 42 => "towel", + _ => "world", + } +} + +// EMIT_MIR single_use_consts.if_const_debug.SingleUseConsts.diff +fn if_const_debug<T: MyTrait>() -> i32 { + // CHECK-LABEL: fn if_const_debug( + // CHECK: my_bool => const <T as MyTrait>::ASSOC_BOOL; + // FIXME: `if` forces a temporary (unlike `match`), so the const isn't direct + // CHECK: _3 = const <T as MyTrait>::ASSOC_BOOL; + // CHECK: switchInt(move _3) + let my_bool = T::ASSOC_BOOL; + do_whatever(); + if my_bool { 7 } else { 42 } +} + +// EMIT_MIR single_use_consts.match_const_debug.SingleUseConsts.diff +fn match_const_debug<T: MyTrait>() -> &'static str { + // CHECK-LABEL: fn match_const_debug( + // CHECK: my_int => const <T as MyTrait>::ASSOC_INT; + // CHECK: switchInt(const <T as MyTrait>::ASSOC_INT) + let my_int = T::ASSOC_INT; + do_whatever(); + match my_int { + 7 => "hello", + 42 => "towel", + _ => "world", + } +} + +// EMIT_MIR single_use_consts.never_used_debug.SingleUseConsts.diff +#[allow(unused_variables)] +fn never_used_debug<T: MyTrait>() { + // CHECK-LABEL: fn never_used_debug( + // CHECK: my_int => const <T as MyTrait>::ASSOC_INT; + // CHECK-NOT: ASSOC_INT + // CHECK: nop + // CHECK-NOT: ASSOC_INT + let my_int = T::ASSOC_INT; +} + +// EMIT_MIR single_use_consts.assign_const_to_return.SingleUseConsts.diff +fn assign_const_to_return<T: MyTrait>() -> bool { + // CHECK-LABEL: fn assign_const_to_return( + // CHECK: _0 = const <T as MyTrait>::ASSOC_BOOL; + T::ASSOC_BOOL +} + +// EMIT_MIR single_use_consts.keep_parameter.SingleUseConsts.diff +fn keep_parameter<T: MyTrait>(mut other: i32) { + // CHECK-LABEL: fn keep_parameter( + // CHECK: _1 = const <T as MyTrait>::ASSOC_INT; + // CHECK: _0 = const (); + other = T::ASSOC_INT; +} + +fn do_whatever() {} diff --git a/tests/mir-opt/sroa/lifetimes.rs b/tests/mir-opt/sroa/lifetimes.rs index 6c18dbaf5a2..90aa2a10938 100644 --- a/tests/mir-opt/sroa/lifetimes.rs +++ b/tests/mir-opt/sroa/lifetimes.rs @@ -19,10 +19,7 @@ fn foo<T: Err>() { // CHECK-NOT: [foo:_.*]: Foo // CHECK-NOT: Box<dyn std::fmt::Display + 'static> - let foo: Foo<T> = Foo { - x: Ok(Box::new(5_u32)), - y: 7_u32, - }; + let foo: Foo<T> = Foo { x: Ok(Box::new(5_u32)), y: 7_u32 }; let x = foo.x; let y = foo.y; diff --git a/tests/mir-opt/switch_to_self.rs b/tests/mir-opt/switch_to_self.rs index fc270fd33cf..51a7c13494f 100644 --- a/tests/mir-opt/switch_to_self.rs +++ b/tests/mir-opt/switch_to_self.rs @@ -8,7 +8,7 @@ use std::intrinsics::mir::*; // EMIT_MIR switch_to_self.test.MatchBranchSimplification.diff #[custom_mir(dialect = "runtime", phase = "post-cleanup")] pub fn test(x: bool) { - mir!( + mir! { { Goto(bb0) } @@ -18,5 +18,5 @@ pub fn test(x: bool) { bb1 = { match x { false => bb0, _ => bb1 } } - ) + } } diff --git a/tests/mir-opt/uninhabited_enum.rs b/tests/mir-opt/uninhabited_enum.rs index 8816f31f9df..859535852cf 100644 --- a/tests/mir-opt/uninhabited_enum.rs +++ b/tests/mir-opt/uninhabited_enum.rs @@ -6,15 +6,15 @@ pub enum Void {} // EMIT_MIR uninhabited_enum.process_never.SimplifyLocals-final.after.mir #[no_mangle] pub fn process_never(input: *const !) { - let _input = unsafe { &*input }; + let _input = unsafe { &*input }; } // EMIT_MIR uninhabited_enum.process_void.SimplifyLocals-final.after.mir #[no_mangle] pub fn process_void(input: *const Void) { - let _input = unsafe { &*input }; - // In the future, this should end with `unreachable`, but we currently only do - // unreachability analysis for `!`. + let _input = unsafe { &*input }; + // In the future, this should end with `unreachable`, but we currently only do + // unreachability analysis for `!`. } fn main() {} diff --git a/tests/mir-opt/unnamed-fields/field_access.rs b/tests/mir-opt/unnamed-fields/field_access.rs index 5badfa1646b..cc0ac9a3427 100644 --- a/tests/mir-opt/unnamed-fields/field_access.rs +++ b/tests/mir-opt/unnamed-fields/field_access.rs @@ -17,7 +17,7 @@ struct Foo { _: struct { d: [u8; 1], } - } + }, } #[repr(C)] @@ -31,10 +31,9 @@ union Bar { _: union { d: [u8; 1], } - } + }, } - fn access<T>(_: T) {} // CHECK-LABEL: fn foo( @@ -71,5 +70,4 @@ fn bar(bar: Bar) { } } - fn main() {} diff --git a/tests/mir-opt/unreachable.rs b/tests/mir-opt/unreachable.rs index 5838b35a553..881e3542f0a 100644 --- a/tests/mir-opt/unreachable.rs +++ b/tests/mir-opt/unreachable.rs @@ -35,7 +35,7 @@ fn if_let() { _y = 42; } - match _x { } + match _x {} } } @@ -56,7 +56,7 @@ fn as_match() { // CHECK: return; match empty() { None => {} - Some(_x) => match _x {} + Some(_x) => match _x {}, } } diff --git a/tests/mir-opt/unusual_item_types.rs b/tests/mir-opt/unusual_item_types.rs index 78847543104..2f05981e812 100644 --- a/tests/mir-opt/unusual_item_types.rs +++ b/tests/mir-opt/unusual_item_types.rs @@ -3,7 +3,6 @@ // that we don't create filenames containing `<` and `>` //@ compile-flags: -Zmir-opt-level=0 - struct A; // EMIT_MIR unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.built.after.mir @@ -23,8 +22,8 @@ enum E { V = 5, } +// EMIT_MIR core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir pub fn main() { let f = Test::X as fn(usize) -> Test; -// EMIT_MIR core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir let v = Vec::<i32>::new(); } diff --git a/tests/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.built.after.mir b/tests/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.built.after.mir index a5121ae550d..e2edbfcd4fa 100644 --- a/tests/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.built.after.mir +++ b/tests/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.built.after.mir @@ -1,6 +1,6 @@ -// MIR for `<impl at $DIR/unusual_item_types.rs:10:1: 10:7>::ASSOCIATED_CONSTANT` after built +// MIR for `<impl at $DIR/unusual_item_types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT` after built -const <impl at $DIR/unusual_item_types.rs:10:1: 10:7>::ASSOCIATED_CONSTANT: i32 = { +const <impl at $DIR/unusual_item_types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT: i32 = { let mut _0: i32; bb0: { diff --git a/tests/pretty/ast-stmt-expr-attr.rs b/tests/pretty/ast-stmt-expr-attr.rs index 899f7173f70..fd7272a1b1f 100644 --- a/tests/pretty/ast-stmt-expr-attr.rs +++ b/tests/pretty/ast-stmt-expr-attr.rs @@ -13,17 +13,17 @@ fn syntax() { let _ = #[attr] (); let _ = #[attr] (#[attr] 0,); let _ = #[attr] (#[attr] 0, 0); - let _ = (#[attr] 0) + #[attr] 0; - let _ = (#[attr] 0) / #[attr] 0; - let _ = (#[attr] 0) & #[attr] 0; - let _ = (#[attr] 0) % #[attr] 0; + let _ = #[attr] 0 + #[attr] 0; + let _ = #[attr] 0 / #[attr] 0; + let _ = #[attr] 0 & #[attr] 0; + let _ = #[attr] 0 % #[attr] 0; let _ = #[attr] (0 + 0); let _ = #[attr] !0; let _ = #[attr] -0; let _ = #[attr] false; let _ = #[attr] 0; let _ = #[attr] 'c'; - let _ = (#[attr] x) as Y; + let _ = #[attr] x as Y; let _ = #[attr] (x as Y); let _ = #[attr] while true { @@ -88,9 +88,9 @@ fn syntax() { let _ = (); foo }; - let _ = (#[attr] x) = y; + let _ = #[attr] x = y; let _ = #[attr] (x = y); - let _ = (#[attr] x) += y; + let _ = #[attr] x += y; let _ = #[attr] (x += y); let _ = #[attr] foo.bar; let _ = (#[attr] foo).bar; @@ -98,8 +98,8 @@ fn syntax() { let _ = (#[attr] foo).0; let _ = #[attr] foo[bar]; let _ = (#[attr] foo)[bar]; - let _ = (#[attr] 0)..#[attr] 0; - let _ = (#[attr] 0)..; + let _ = #[attr] 0..#[attr] 0; + let _ = #[attr] 0..; let _ = #[attr] (0..0); let _ = #[attr] (0..); let _ = #[attr] (..0); diff --git a/tests/pretty/hir-fn-variadic.pp b/tests/pretty/hir-fn-variadic.pp index 978e65c825b..dfbaff69644 100644 --- a/tests/pretty/hir-fn-variadic.pp +++ b/tests/pretty/hir-fn-variadic.pp @@ -9,7 +9,7 @@ use ::std::prelude::rust_2015::*; extern crate std; extern "C" { - fn foo(x: i32, va1: ...); + unsafe fn foo(x: i32, va1: ...); } unsafe extern "C" fn bar(_: i32, mut va2: ...) -> usize { va2.arg::<usize>() } diff --git a/tests/pretty/stmt_expr_attributes.rs b/tests/pretty/stmt_expr_attributes.rs index f9041268211..01a503ce7ee 100644 --- a/tests/pretty/stmt_expr_attributes.rs +++ b/tests/pretty/stmt_expr_attributes.rs @@ -147,13 +147,13 @@ fn _11() { let _ = #[rustc_dummy] (0); let _ = #[rustc_dummy] (0,); let _ = #[rustc_dummy] (0, 0); - let _ = (#[rustc_dummy] 0) + #[rustc_dummy] 0; + let _ = #[rustc_dummy] 0 + #[rustc_dummy] 0; let _ = #[rustc_dummy] !0; let _ = #[rustc_dummy] -0i32; let _ = #[rustc_dummy] false; let _ = #[rustc_dummy] 'c'; let _ = #[rustc_dummy] 0; - let _ = (#[rustc_dummy] 0) as usize; + let _ = #[rustc_dummy] 0 as usize; let _ = #[rustc_dummy] while false { #![rustc_dummy] @@ -206,10 +206,15 @@ fn _11() { let _ = (); () }; - let const {} = #[rustc_dummy] const {}; + let const { + #![rustc_dummy] + } = + #[rustc_dummy] const { + #![rustc_dummy] + }; let mut x = 0; - let _ = (#[rustc_dummy] x) = 15; - let _ = (#[rustc_dummy] x) += 15; + let _ = #[rustc_dummy] x = 15; + let _ = #[rustc_dummy] x += 15; let s = Foo { data: () }; let _ = #[rustc_dummy] s.data; let _ = (#[rustc_dummy] s).data; @@ -219,8 +224,8 @@ fn _11() { let v = vec!(0); let _ = #[rustc_dummy] v[0]; let _ = (#[rustc_dummy] v)[0]; - let _ = (#[rustc_dummy] 0)..#[rustc_dummy] 0; - let _ = (#[rustc_dummy] 0)..; + let _ = #[rustc_dummy] 0..#[rustc_dummy] 0; + let _ = #[rustc_dummy] 0..; let _ = #[rustc_dummy] (0..0); let _ = #[rustc_dummy] (0..); let _ = #[rustc_dummy] (..0); diff --git a/tests/run-make-fulldeps/hotplug_codegen_backend/Makefile b/tests/run-make-fulldeps/hotplug_codegen_backend/Makefile deleted file mode 100644 index 3a5a66b6755..00000000000 --- a/tests/run-make-fulldeps/hotplug_codegen_backend/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -include ../../run-make/tools.mk - -# ignore-stage1 - -# This test both exists as a check that -Zcodegen-backend is capable of loading external codegen -# backends and that this external codegen backend is only included in the dep info if -# -Zbinary-dep-depinfo is used. - -all: - $(RUSTC) the_backend.rs --crate-name the_backend --crate-type dylib \ - -o $(TMPDIR)/the_backend.dylib - - $(RUSTC) some_crate.rs --crate-name some_crate --crate-type lib -o $(TMPDIR)/some_crate \ - -Z codegen-backend=$(TMPDIR)/the_backend.dylib -Z unstable-options \ - --emit link,dep-info - grep -x "This has been \"compiled\" successfully." $(TMPDIR)/libsome_crate.rlib - # don't declare a dependency on the codegen backend if -Zbinary-dep-depinfo isn't used. - grep -v "the_backend.dylib" $(TMPDIR)/some_crate.d - - $(RUSTC) some_crate.rs --crate-name some_crate --crate-type lib -o $(TMPDIR)/some_crate \ - -Z codegen-backend=$(TMPDIR)/the_backend.dylib -Z unstable-options \ - --emit link,dep-info -Zbinary-dep-depinfo - grep -x "This has been \"compiled\" successfully." $(TMPDIR)/libsome_crate.rlib - # but declare a dependency on the codegen backend if -Zbinary-dep-depinfo it used. - grep "the_backend.dylib" $(TMPDIR)/some_crate.d diff --git a/tests/run-make-fulldeps/hotplug_codegen_backend/some_crate.rs b/tests/run-make-fulldeps/hotplug_codegen_backend/some_crate.rs deleted file mode 100644 index da27b7f3463..00000000000 --- a/tests/run-make-fulldeps/hotplug_codegen_backend/some_crate.rs +++ /dev/null @@ -1,2 +0,0 @@ -#![feature(no_core)] -#![no_core] diff --git a/tests/run-make-fulldeps/issue-19371/Makefile b/tests/run-make-fulldeps/issue-19371/Makefile deleted file mode 100644 index edec68f0862..00000000000 --- a/tests/run-make-fulldeps/issue-19371/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -include ../../run-make/tools.mk - -# This test ensures that rustc compile_input can be called twice in one task -# without causing a panic. -# The program needs the path to rustc to get sysroot. - -all: - $(RUSTC) foo.rs - $(call RUN,foo $(TMPDIR) $(RUSTC)) diff --git a/tests/run-make-fulldeps/obtain-borrowck/Makefile b/tests/run-make-fulldeps/obtain-borrowck/Makefile deleted file mode 100644 index 233f5c9eaf4..00000000000 --- a/tests/run-make-fulldeps/obtain-borrowck/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -include ../../run-make/tools.mk - -# This example shows how to implement a rustc driver that retrieves MIR bodies -# together with the borrow checker information. - -# How to run this -# $ ./x.py test tests/run-make-fulldeps/obtain-borrowck - -DRIVER_BINARY := "$(TMPDIR)"/driver -SYSROOT := $(shell $(RUSTC) --print sysroot) - -ifdef IS_WINDOWS -LIBSTD := -L "$(SYSROOT)\\lib\\rustlib\\$(TARGET)\\lib" -else -LIBSTD := -endif - -all: - $(RUSTC) driver.rs -o "$(DRIVER_BINARY)" - $(TARGET_RPATH_ENV) "$(DRIVER_BINARY)" --sysroot $(SYSROOT) $(LIBSTD) test.rs -o "$(TMPDIR)/driver_test" > "$(TMPDIR)"/output.stdout - -ifdef RUSTC_BLESS_TEST - cp "$(TMPDIR)"/output.stdout output.stdout -else - $(DIFF) output.stdout "$(TMPDIR)"/output.stdout -endif diff --git a/tests/run-make-fulldeps/pretty-expanded/Makefile b/tests/run-make-fulldeps/pretty-expanded/Makefile deleted file mode 100644 index 48199179ece..00000000000 --- a/tests/run-make-fulldeps/pretty-expanded/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -include ../../run-make/tools.mk - -all: - $(RUSTC) -o $(TMPDIR)/input.expanded.rs -Zunpretty=expanded input.rs diff --git a/tests/run-make-fulldeps/pretty-expanded/input.rs b/tests/run-make-fulldeps/pretty-expanded/input.rs deleted file mode 100644 index 02b235068a1..00000000000 --- a/tests/run-make-fulldeps/pretty-expanded/input.rs +++ /dev/null @@ -1,8 +0,0 @@ -// #13544 - -#[derive(Debug)] pub struct A; -#[derive(Debug)] pub struct B(isize); -#[derive(Debug)] pub struct C { x: isize } -#[derive(Debug)] pub enum D {} -#[derive(Debug)] pub enum E { y } -#[derive(Debug)] pub enum F { z(isize) } diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs index 1bdb6347571..f913aedcde7 100644 --- a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs +++ b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs @@ -5,19 +5,15 @@ use std::path::PathBuf; -use run_make_support::{aux_build, rustc}; +use run_make_support::{aux_build, rustc, source_root}; fn main() { aux_build().input("stable.rs").emit("metadata").run(); - 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).command_output(); + rustc().input("main.rs").emit("metadata").extern_("stable", "libstable.rmeta").run(); - let stderr = String::from_utf8_lossy(&output.stderr); - let version = include_str!(concat!(env!("S"), "/src/version")); + let version = std::fs::read_to_string(source_root().join("src/version")).unwrap(); let expected_string = format!("stable since {}", version.trim()); - assert!(stderr.contains(&expected_string)); + output.assert_stderr_contains(expected_string); } diff --git a/tests/run-make/README.md b/tests/run-make/README.md new file mode 100644 index 00000000000..a6c1b4b7db7 --- /dev/null +++ b/tests/run-make/README.md @@ -0,0 +1,43 @@ +# The `run-make` test suite + +The `run-make` test suite contains tests which are the most flexible out of all +the [rust-lang/rust](https://github.com/rust-lang/rust) test suites. `run-make` +tests can basically contain arbitrary code, and are supported by the +[`run_make_support`] library. + +## Infrastructure + +There are two kinds of run-make tests: + +1. The new `rmake.rs` version: this allows run-make tests to be written in Rust + (with `rmake.rs` as the main test file). +2. The legacy `Makefile` version: this is what run-make tests were written with + before support for `rmake.rs` was introduced. + +The implementation for collecting and building the `rmake.rs` recipes (or +`Makefile`s) are in +[`src/tools/compiletest/src/runtest.rs`](../../src/tools/compiletest/src/runtest.rs), +in `run_rmake_v2_test` and `run_rmake_legacy_test`. + +### Rust-based `run-make` tests: `rmake.rs` + +The setup for the `rmake.rs` version is a 3-stage process: + +1. First, we build the [`run_make_support`] library in bootstrap as a tool lib. +2. Then, we compile the `rmake.rs` "recipe" linking the support library and its + dependencies in, and provide a bunch of env vars. We setup a directory + structure within `build/<target>/test/run-make/` + + ``` + <test-name>/ + rmake.exe # recipe binary + rmake_out/ # sources from test sources copied over + ``` + + and copy non-`rmake.rs` input support files over to `rmake_out/`. The + support library is made available as an [*extern prelude*][extern_prelude]. +3. Finally, we run the recipe binary and set `rmake_out/` as the working + directory. + +[`run_make_support`]: ../../src/tools/run-make-support +[extern_prelude]: https://doc.rust-lang.org/reference/names/preludes.html#extern-prelude diff --git a/tests/run-make/alloc-no-oom-handling/rmake.rs b/tests/run-make/alloc-no-oom-handling/rmake.rs index 4bca5d1f1ef..89a6636d9a0 100644 --- a/tests/run-make/alloc-no-oom-handling/rmake.rs +++ b/tests/run-make/alloc-no-oom-handling/rmake.rs @@ -2,14 +2,14 @@ // when the unstable no_global_oom_handling feature is turned on. // See https://github.com/rust-lang/rust/pull/84266 -use run_make_support::rustc; +use run_make_support::{rustc, source_root}; fn main() { rustc() .edition("2021") .arg("-Dwarnings") .crate_type("rlib") - .input("../../../library/alloc/src/lib.rs") + .input(source_root().join("library/alloc/src/lib.rs")) .cfg("no_global_oom_handling") .run(); } diff --git a/tests/run-make/alloc-no-rc/rmake.rs b/tests/run-make/alloc-no-rc/rmake.rs index 8ff73324b08..12171c2148f 100644 --- a/tests/run-make/alloc-no-rc/rmake.rs +++ b/tests/run-make/alloc-no-rc/rmake.rs @@ -2,14 +2,14 @@ // when the unstable no_rc feature is turned on. // See https://github.com/rust-lang/rust/pull/84266 -use run_make_support::rustc; +use run_make_support::{rustc, source_root}; fn main() { rustc() .edition("2021") .arg("-Dwarnings") .crate_type("rlib") - .input("../../../library/alloc/src/lib.rs") + .input(source_root().join("library/alloc/src/lib.rs")) .cfg("no_rc") .run(); } diff --git a/tests/run-make/alloc-no-sync/rmake.rs b/tests/run-make/alloc-no-sync/rmake.rs index 3a3ceed6867..29f204f3067 100644 --- a/tests/run-make/alloc-no-sync/rmake.rs +++ b/tests/run-make/alloc-no-sync/rmake.rs @@ -2,14 +2,14 @@ // when the unstable no_sync feature is turned on. // See https://github.com/rust-lang/rust/pull/84266 -use run_make_support::rustc; +use run_make_support::{rustc, source_root}; fn main() { rustc() .edition("2021") .arg("-Dwarnings") .crate_type("rlib") - .input("../../../library/alloc/src/lib.rs") + .input(source_root().join("library/alloc/src/lib.rs")) .cfg("no_sync") .run(); } diff --git a/tests/run-make/allow-warnings-cmdline-stability/rmake.rs b/tests/run-make/allow-warnings-cmdline-stability/rmake.rs index 8f6fe6bd0b6..22a31266176 100644 --- a/tests/run-make/allow-warnings-cmdline-stability/rmake.rs +++ b/tests/run-make/allow-warnings-cmdline-stability/rmake.rs @@ -1,11 +1,13 @@ // Test that `-Awarnings` suppresses warnings for unstable APIs. -use run_make_support::{assert_not_contains, rustc}; +use run_make_support::rustc; fn main() { rustc().input("bar.rs").run(); - let output = rustc().input("foo.rs").arg("-Awarnings").run(); - - assert_not_contains(&String::from_utf8(output.stdout).unwrap(), "warning"); - assert_not_contains(&String::from_utf8(output.stderr).unwrap(), "warning"); + rustc() + .input("foo.rs") + .arg("-Awarnings") + .run() + .assert_stdout_not_contains("warning") + .assert_stderr_not_contains("warning"); } diff --git a/tests/run-make/arguments-non-c-like-enum/rmake.rs b/tests/run-make/arguments-non-c-like-enum/rmake.rs index 13230206ca8..88f4d664aa6 100644 --- a/tests/run-make/arguments-non-c-like-enum/rmake.rs +++ b/tests/run-make/arguments-non-c-like-enum/rmake.rs @@ -1,14 +1,14 @@ //! Check that non-trivial `repr(C)` enum in Rust has valid C layout. //@ ignore-cross-compile -use run_make_support::{cc, extra_c_flags, extra_cxx_flags, run, rustc, static_lib}; +use run_make_support::{cc, extra_c_flags, extra_cxx_flags, run, rustc, static_lib_name}; pub fn main() { use std::path::Path; rustc().input("nonclike.rs").crate_type("staticlib").run(); cc().input("test.c") - .input(static_lib("nonclike")) + .input(static_lib_name("nonclike")) .out_exe("test") .args(&extra_c_flags()) .args(&extra_cxx_flags()) diff --git a/tests/run-make/artifact-incr-cache-no-obj/rmake.rs b/tests/run-make/artifact-incr-cache-no-obj/rmake.rs index 6613698ae1d..d5bc46dff47 100644 --- a/tests/run-make/artifact-incr-cache-no-obj/rmake.rs +++ b/tests/run-make/artifact-incr-cache-no-obj/rmake.rs @@ -5,17 +5,15 @@ // // Fixes: rust-lang/rust#123234 -use run_make_support::{rustc, tmp_dir}; +use run_make_support::rustc; fn main() { - let inc_dir = tmp_dir(); - for _ in 0..=1 { rustc() .input("lib.rs") .crate_type("lib") .emit("asm,dep-info,link,mir,llvm-ir,llvm-bc") - .incremental(&inc_dir) + .incremental("incremental") .run(); } } diff --git a/tests/run-make/artifact-incr-cache/rmake.rs b/tests/run-make/artifact-incr-cache/rmake.rs index 106f363eb8d..b4b63313cfc 100644 --- a/tests/run-make/artifact-incr-cache/rmake.rs +++ b/tests/run-make/artifact-incr-cache/rmake.rs @@ -7,17 +7,15 @@ // Also see discussion at // <https://internals.rust-lang.org/t/interaction-between-incremental-compilation-and-emit/20551> -use run_make_support::{rustc, tmp_dir}; +use run_make_support::rustc; fn main() { - let inc_dir = tmp_dir(); - for _ in 0..=1 { rustc() .input("lib.rs") .crate_type("lib") .emit("obj,asm,dep-info,link,mir,llvm-ir,llvm-bc") - .incremental(&inc_dir) + .incremental("incremental") .run(); } } diff --git a/tests/run-make/bare-outfile/Makefile b/tests/run-make/bare-outfile/Makefile deleted file mode 100644 index ad6fe4bd167..00000000000 --- a/tests/run-make/bare-outfile/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# 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 - -all: - cp foo.rs $(TMPDIR) - cd $(TMPDIR) && $(RUSTC) -o foo foo.rs - $(call RUN,foo) diff --git a/tests/run-make/bare-outfile/rmake.rs b/tests/run-make/bare-outfile/rmake.rs new file mode 100644 index 00000000000..badf1396b73 --- /dev/null +++ b/tests/run-make/bare-outfile/rmake.rs @@ -0,0 +1,11 @@ +// 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 + +use run_make_support::{run, rustc}; + +fn main() { + rustc().output("foo").input("foo.rs").run(); + run("foo"); +} diff --git a/tests/run-make/box-struct-no-segfault/rmake.rs b/tests/run-make/box-struct-no-segfault/rmake.rs index 5406f765e6c..1bbefd03541 100644 --- a/tests/run-make/box-struct-no-segfault/rmake.rs +++ b/tests/run-make/box-struct-no-segfault/rmake.rs @@ -5,9 +5,9 @@ // This test checks that this bug does not resurface. // See https://github.com/rust-lang/rust/issues/28766 -use run_make_support::{rustc, tmp_dir}; +use run_make_support::rustc; fn main() { rustc().opt().input("foo.rs").run(); - rustc().opt().library_search_path(tmp_dir()).input("main.rs").run(); + rustc().opt().input("main.rs").run(); } diff --git a/tests/run-make/c-link-to-rust-dylib/rmake.rs b/tests/run-make/c-link-to-rust-dylib/rmake.rs index 5c4b6d78649..ec42e88032d 100644 --- a/tests/run-make/c-link-to-rust-dylib/rmake.rs +++ b/tests/run-make/c-link-to-rust-dylib/rmake.rs @@ -5,29 +5,23 @@ use std::fs::remove_file; -use run_make_support::{ - cc, dynamic_lib_extension, is_msvc, read_dir, run, run_fail, rustc, tmp_dir, -}; +use run_make_support::{cc, cwd, dynamic_lib_extension, is_msvc, read_dir, run, run_fail, rustc}; fn main() { rustc().input("foo.rs").run(); if is_msvc() { - let lib = tmp_dir().join("foo.dll.lib"); + let lib = "foo.dll.lib"; cc().input("bar.c").arg(lib).out_exe("bar").run(); } else { - cc().input("bar.c") - .arg("-lfoo") - .output(tmp_dir().join("bar")) - .library_search_path(tmp_dir()) - .run(); + cc().input("bar.c").arg("-lfoo").output("bar").library_search_path(cwd()).run(); } run("bar"); let expected_extension = dynamic_lib_extension(); - read_dir(tmp_dir(), |path| { + read_dir(cwd(), |path| { if path.is_file() && path.extension().is_some_and(|ext| ext == expected_extension) && path.file_name().and_then(|name| name.to_str()).is_some_and(|name| { diff --git a/tests/run-make/c-link-to-rust-staticlib/rmake.rs b/tests/run-make/c-link-to-rust-staticlib/rmake.rs index 63d5eb78c69..ca28944a026 100644 --- a/tests/run-make/c-link-to-rust-staticlib/rmake.rs +++ b/tests/run-make/c-link-to-rust-staticlib/rmake.rs @@ -3,13 +3,13 @@ //@ ignore-cross-compile -use run_make_support::{cc, extra_c_flags, run, rustc, static_lib}; +use run_make_support::{cc, extra_c_flags, run, rustc, static_lib_name}; use std::fs; fn main() { rustc().input("foo.rs").run(); - cc().input("bar.c").input(static_lib("foo")).out_exe("bar").args(&extra_c_flags()).run(); + cc().input("bar.c").input(static_lib_name("foo")).out_exe("bar").args(&extra_c_flags()).run(); run("bar"); - fs::remove_file(static_lib("foo")); + fs::remove_file(static_lib_name("foo")); run("bar"); } diff --git a/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs index 7a450efff94..a01e259bce0 100644 --- a/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs +++ b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs @@ -5,12 +5,12 @@ //@ ignore-cross-compile -use run_make_support::{cc, extra_c_flags, run, rustc, static_lib}; +use run_make_support::{cc, extra_c_flags, run, rustc, static_lib_name}; fn main() { rustc().input("checkrust.rs").run(); cc().input("test.c") - .input(static_lib("checkrust")) + .input(static_lib_name("checkrust")) .out_exe("test") .args(&extra_c_flags()) .run(); diff --git a/tests/run-make/cdylib/rmake.rs b/tests/run-make/cdylib/rmake.rs index fcb4f56621f..81166867b79 100644 --- a/tests/run-make/cdylib/rmake.rs +++ b/tests/run-make/cdylib/rmake.rs @@ -12,24 +12,20 @@ use std::fs::remove_file; -use run_make_support::{cc, dynamic_lib, is_msvc, run, rustc, tmp_dir}; +use run_make_support::{cc, cwd, dynamic_lib_name, is_msvc, run, rustc}; fn main() { rustc().input("bar.rs").run(); rustc().input("foo.rs").run(); if is_msvc() { - cc().input("foo.c").arg(tmp_dir().join("foo.dll.lib")).out_exe("foo").run(); + cc().input("foo.c").arg("foo.dll.lib").out_exe("foo").run(); } else { - cc().input("foo.c") - .arg("-lfoo") - .output(tmp_dir().join("foo")) - .library_search_path(tmp_dir()) - .run(); + cc().input("foo.c").arg("-lfoo").library_search_path(cwd()).output("foo").run(); } run("foo"); - remove_file(dynamic_lib("foo")).unwrap(); + remove_file(dynamic_lib_name("foo")).unwrap(); rustc().input("foo.rs").arg("-Clto").run(); run("foo"); diff --git a/tests/run-make/compiler-builtins/Cargo.toml b/tests/run-make/compiler-builtins/Cargo.toml new file mode 100644 index 00000000000..869210c4a68 --- /dev/null +++ b/tests/run-make/compiler-builtins/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "scratch" +version = "0.1.0" +edition = "2021" + +[lib] +path = "lib.rs" diff --git a/tests/run-make/compiler-builtins/lib.rs b/tests/run-make/compiler-builtins/lib.rs new file mode 100644 index 00000000000..0c9ac1ac8e4 --- /dev/null +++ b/tests/run-make/compiler-builtins/lib.rs @@ -0,0 +1 @@ +#![no_std] diff --git a/tests/run-make/compiler-builtins/rmake.rs b/tests/run-make/compiler-builtins/rmake.rs index f5da50ebb04..a2c0ad5f6de 100644 --- a/tests/run-make/compiler-builtins/rmake.rs +++ b/tests/run-make/compiler-builtins/rmake.rs @@ -14,40 +14,27 @@ #![deny(warnings)] -use run_make_support::object; use run_make_support::object::read::archive::ArchiveFile; use run_make_support::object::read::Object; use run_make_support::object::ObjectSection; use run_make_support::object::ObjectSymbol; use run_make_support::object::RelocationTarget; -use run_make_support::set_host_rpath; -use run_make_support::tmp_dir; +use run_make_support::{cmd, env_var, object}; use std::collections::HashSet; - -const MANIFEST: &str = r#" -[package] -name = "scratch" -version = "0.1.0" -edition = "2021" - -[lib] -path = "lib.rs""#; +use std::path::PathBuf; fn main() { - let target_dir = tmp_dir().join("target"); - let target = std::env::var("TARGET").unwrap(); + let target_dir = PathBuf::from("target"); + let target = env_var("TARGET"); println!("Testing compiler_builtins for {}", target); - // Set up the tiniest Cargo project: An empty no_std library. Just enough to run -Zbuild-std. - let manifest_path = tmp_dir().join("Cargo.toml"); - std::fs::write(&manifest_path, MANIFEST.as_bytes()).unwrap(); - std::fs::write(tmp_dir().join("lib.rs"), b"#![no_std]").unwrap(); + let manifest_path = PathBuf::from("Cargo.toml"); - let path = std::env::var("PATH").unwrap(); - let rustc = std::env::var("RUSTC").unwrap(); - let bootstrap_cargo = std::env::var("BOOTSTRAP_CARGO").unwrap(); - let mut cmd = std::process::Command::new(bootstrap_cargo); + let path = env_var("PATH"); + let rustc = env_var("RUSTC"); + let bootstrap_cargo = env_var("BOOTSTRAP_CARGO"); + let mut cmd = cmd(bootstrap_cargo); cmd.args([ "build", "--manifest-path", @@ -56,7 +43,6 @@ fn main() { "--target", &target, ]) - .env_clear() .env("PATH", path) .env("RUSTC", rustc) .env("RUSTFLAGS", "-Copt-level=0 -Cdebug-assertions=yes") @@ -65,10 +51,8 @@ fn main() { // Visual Studio 2022 requires that the LIB env var be set so it can // find the Windows SDK. .env("LIB", std::env::var("LIB").unwrap_or_default()); - set_host_rpath(&mut cmd); - let status = cmd.status().unwrap(); - assert!(status.success()); + cmd.run(); let rlibs_path = target_dir.join(target).join("debug").join("deps"); let compiler_builtins_rlib = std::fs::read_dir(rlibs_path) diff --git a/tests/run-make/const-prop-lint/rmake.rs b/tests/run-make/const-prop-lint/rmake.rs index fa27a18a591..c35294f2f5a 100644 --- a/tests/run-make/const-prop-lint/rmake.rs +++ b/tests/run-make/const-prop-lint/rmake.rs @@ -2,12 +2,12 @@ use std::fs; -use run_make_support::{rustc, tmp_dir}; +use run_make_support::{cwd, rustc}; fn main() { - rustc().input("input.rs").run_fail_assert_exit_code(1); + rustc().input("input.rs").run_fail().assert_exit_code(1); - for entry in fs::read_dir(tmp_dir()).unwrap() { + for entry in fs::read_dir(cwd()).unwrap() { let entry = entry.unwrap(); let path = entry.path(); diff --git a/tests/run-make/core-no-fp-fmt-parse/rmake.rs b/tests/run-make/core-no-fp-fmt-parse/rmake.rs index aef28fd2528..3586922f28e 100644 --- a/tests/run-make/core-no-fp-fmt-parse/rmake.rs +++ b/tests/run-make/core-no-fp-fmt-parse/rmake.rs @@ -1,14 +1,14 @@ // This test checks that the core library of Rust can be compiled without enabling // support for formatting and parsing floating-point numbers. -use run_make_support::rustc; +use run_make_support::{rustc, source_root}; fn main() { rustc() .edition("2021") .arg("-Dwarnings") .crate_type("rlib") - .input("../../../library/core/src/lib.rs") + .input(source_root().join("library/core/src/lib.rs")) .cfg("no_fp_fmt_parse") .run(); } diff --git a/tests/run-make/core-no-oom-handling/rmake.rs b/tests/run-make/core-no-oom-handling/rmake.rs index 75767421cd1..a9e2b33e210 100644 --- a/tests/run-make/core-no-oom-handling/rmake.rs +++ b/tests/run-make/core-no-oom-handling/rmake.rs @@ -2,15 +2,15 @@ // when the no_global_oom_handling feature is turned on. // See https://github.com/rust-lang/rust/pull/110649 -use run_make_support::{rustc, tmp_dir}; +use run_make_support::{rustc, source_root}; fn main() { rustc() .edition("2021") .arg("-Dwarnings") .crate_type("rlib") - .input("../../../library/core/src/lib.rs") - .sysroot(tmp_dir().join("fakeroot")) + .input(source_root().join("library/core/src/lib.rs")) + .sysroot("fakeroot") .cfg("no_global_oom_handling") .run(); } diff --git a/tests/run-make/crate-data-smoke/rmake.rs b/tests/run-make/crate-data-smoke/rmake.rs index 86fe5593e66..70f8e46b6d9 100644 --- a/tests/run-make/crate-data-smoke/rmake.rs +++ b/tests/run-make/crate-data-smoke/rmake.rs @@ -1,22 +1,21 @@ -use std::process::Output; - use run_make_support::{bin_name, rust_lib_name, rustc}; -fn compare_stdout<S: AsRef<str>>(output: Output, expected: S) { - assert_eq!(String::from_utf8(output.stdout).unwrap().trim(), expected.as_ref()); -} - fn main() { - compare_stdout(rustc().print("crate-name").input("crate.rs").run(), "foo"); - compare_stdout(rustc().print("file-names").input("crate.rs").run(), bin_name("foo")); - compare_stdout( - rustc().print("file-names").crate_type("lib").arg("--test").input("crate.rs").run(), - bin_name("foo"), - ); - compare_stdout( - rustc().print("file-names").arg("--test").input("lib.rs").run(), - bin_name("mylib"), - ); - compare_stdout(rustc().print("file-names").input("lib.rs").run(), rust_lib_name("mylib")); - compare_stdout(rustc().print("file-names").input("rlib.rs").run(), rust_lib_name("mylib")); + rustc().print("crate-name").input("crate.rs").run().assert_stdout_equals("foo"); + rustc().print("file-names").input("crate.rs").run().assert_stdout_equals(bin_name("foo")); + rustc() + .print("file-names") + .crate_type("lib") + .arg("--test") + .input("crate.rs") + .run() + .assert_stdout_equals(bin_name("foo")); + rustc() + .print("file-names") + .arg("--test") + .input("lib.rs") + .run() + .assert_stdout_equals(bin_name("mylib")); + rustc().print("file-names").input("lib.rs").run().assert_stdout_equals(rust_lib_name("mylib")); + rustc().print("file-names").input("rlib.rs").run().assert_stdout_equals(rust_lib_name("mylib")); } diff --git a/tests/run-make/cross-lang-lto-clang/Makefile b/tests/run-make/cross-lang-lto-clang/Makefile index acaebf439d6..acf49c8f5c8 100644 --- a/tests/run-make/cross-lang-lto-clang/Makefile +++ b/tests/run-make/cross-lang-lto-clang/Makefile @@ -1,4 +1,4 @@ -# needs-matching-clang +# needs-force-clang-based-tests # This test makes sure that cross-language inlining actually works by checking # the generated machine code. diff --git a/tests/run-make/cross-lang-lto-pgo-smoketest/Makefile b/tests/run-make/cross-lang-lto-pgo-smoketest/Makefile index 70085d9bde1..738e23f9c66 100644 --- a/tests/run-make/cross-lang-lto-pgo-smoketest/Makefile +++ b/tests/run-make/cross-lang-lto-pgo-smoketest/Makefile @@ -1,4 +1,7 @@ -# needs-matching-clang +# needs-force-clang-based-tests + +# FIXME(#126180): This test doesn't actually run anywhere, because the only +# CI job that sets RUSTBUILD_FORCE_CLANG_BASED_TESTS runs very few tests. # This test makes sure that cross-language inlining can be used in conjunction # with profile-guided optimization. The test only tests that the whole workflow diff --git a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs index 61f32762d8b..f40da662128 100644 --- a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs +++ b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs @@ -1,9 +1,12 @@ //! Make sure that cross-language LTO works on riscv targets, //! which requires extra `target-abi` metadata to be emitted. -//@ needs-matching-clang +//@ needs-force-clang-based-tests //@ needs-llvm-components riscv -use run_make_support::{bin_name, clang, llvm_readobj, rustc, tmp_dir}; +// FIXME(#126180): This test doesn't actually run anywhere, because the only +// CI job that sets RUSTBUILD_FORCE_CLANG_BASED_TESTS runs very few tests. + +use run_make_support::{bin_name, clang, llvm_readobj, rustc}; use std::{ env, path::PathBuf, @@ -30,11 +33,11 @@ fn check_target(target: &str, clang_target: &str, carch: &str, is_double_float: .no_stdlib() .out_exe("riscv-xlto") .input("cstart.c") - .input(tmp_dir().join("libriscv_xlto.rlib")) + .input("libriscv_xlto.rlib") .run(); // Check that the built binary has correct float abi - let executable = tmp_dir().join(bin_name("riscv-xlto")); + let executable = bin_name("riscv-xlto"); let output = llvm_readobj().input(&executable).file_header().run(); let stdout = String::from_utf8_lossy(&output.stdout); eprintln!("obj:\n{}", stdout); diff --git a/tests/run-make/deref-impl-rustdoc-ice/rmake.rs b/tests/run-make/deref-impl-rustdoc-ice/rmake.rs index c2156de03a9..91fc0a9025f 100644 --- a/tests/run-make/deref-impl-rustdoc-ice/rmake.rs +++ b/tests/run-make/deref-impl-rustdoc-ice/rmake.rs @@ -7,10 +7,10 @@ //@ ignore-cross-compile -use run_make_support::{rustc, rustdoc, tmp_dir}; +use run_make_support::{cwd, rustc, rustdoc}; fn main() { rustc().input("foo.rs").run(); rustc().input("bar.rs").run(); - rustdoc().input("baz.rs").library_search_path(tmp_dir()).output(tmp_dir()).run(); + rustdoc().input("baz.rs").library_search_path(cwd()).output(cwd()).run(); } diff --git a/tests/run-make/doctests-keep-binaries/rmake.rs b/tests/run-make/doctests-keep-binaries/rmake.rs index 0613ef4839b..5bc9480e4a3 100644 --- a/tests/run-make/doctests-keep-binaries/rmake.rs +++ b/tests/run-make/doctests-keep-binaries/rmake.rs @@ -1,15 +1,15 @@ // Check that valid binaries are persisted by running them, regardless of whether the // --run or --no-run option is used. -use run_make_support::{run, rustc, rustdoc, tmp_dir}; +use run_make_support::{run, rustc, rustdoc}; use std::fs::{create_dir, remove_dir_all}; use std::path::Path; fn setup_test_env<F: FnOnce(&Path, &Path)>(callback: F) { - let out_dir = tmp_dir().join("doctests"); + let out_dir = Path::new("doctests"); create_dir(&out_dir).expect("failed to create doctests folder"); rustc().input("t.rs").crate_type("rlib").run(); - callback(&out_dir, &tmp_dir().join("libt.rlib")); + callback(&out_dir, Path::new("libt.rlib")); remove_dir_all(out_dir); } @@ -44,19 +44,17 @@ fn main() { }); // Behavior with --test-run-directory with relative paths. setup_test_env(|_out_dir, extern_path| { - let run_dir = "rundir"; - let run_dir_path = tmp_dir().join("rundir"); + let run_dir_path = Path::new("rundir"); create_dir(&run_dir_path).expect("failed to create rundir folder"); rustdoc() - .current_dir(tmp_dir()) - .input(std::env::current_dir().unwrap().join("t.rs")) + .input("t.rs") .arg("-Zunstable-options") .arg("--test") .arg("--persist-doctests") .arg("doctests") .arg("--test-run-directory") - .arg(run_dir) + .arg(run_dir_path) .extern_("t", "libt.rlib") .run(); diff --git a/tests/run-make/doctests-runtool/rmake.rs b/tests/run-make/doctests-runtool/rmake.rs index 6cc7c6bbdaf..6a7a931249e 100644 --- a/tests/run-make/doctests-runtool/rmake.rs +++ b/tests/run-make/doctests-runtool/rmake.rs @@ -1,12 +1,11 @@ // Tests behavior of rustdoc `--runtool`. -use run_make_support::{rustc, rustdoc, tmp_dir}; -use std::env::current_dir; +use run_make_support::{rustc, rustdoc}; use std::fs::{create_dir, remove_dir_all}; use std::path::PathBuf; fn mkdir(name: &str) -> PathBuf { - let dir = tmp_dir().join(name); + let dir = PathBuf::from(name); create_dir(&dir).expect("failed to create doctests folder"); dir } @@ -22,7 +21,7 @@ fn main() { rustc().input("runtool.rs").output(&run_tool_binary).run(); rustdoc() - .input(current_dir().unwrap().join("t.rs")) + .input("t.rs") .arg("-Zunstable-options") .arg("--test") .arg("--test-run-directory") @@ -30,7 +29,6 @@ fn main() { .arg("--runtool") .arg(&run_tool_binary) .extern_("t", "libt.rlib") - .current_dir(tmp_dir()) .run(); remove_dir_all(run_dir); diff --git a/tests/run-make/emit-named-files/rmake.rs b/tests/run-make/emit-named-files/rmake.rs index 068f9796d0e..c4b7b9aebf6 100644 --- a/tests/run-make/emit-named-files/rmake.rs +++ b/tests/run-make/emit-named-files/rmake.rs @@ -1,7 +1,7 @@ use std::fs::create_dir; use std::path::Path; -use run_make_support::{rustc, tmp_dir}; +use run_make_support::rustc; fn emit_and_check(out_dir: &Path, out_file: &str, format: &str) { let out_file = out_dir.join(out_file); @@ -10,7 +10,7 @@ fn emit_and_check(out_dir: &Path, out_file: &str, format: &str) { } fn main() { - let out_dir = tmp_dir().join("emit"); + let out_dir = Path::new("emit"); create_dir(&out_dir).unwrap(); diff --git a/tests/run-make/emit/Makefile b/tests/run-make/emit/Makefile deleted file mode 100644 index b3ca0b79fb0..00000000000 --- a/tests/run-make/emit/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) -Copt-level=0 --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs - $(RUSTC) -Copt-level=1 --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs - $(RUSTC) -Copt-level=2 --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs - $(RUSTC) -Copt-level=3 --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs - $(RUSTC) -Copt-level=s --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs - $(RUSTC) -Copt-level=z --emit=llvm-bc,llvm-ir,asm,obj,link test-24876.rs - $(RUSTC) -Copt-level=0 --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs - $(call RUN,test-26235) || exit 1 - $(RUSTC) -Copt-level=1 --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs - $(call RUN,test-26235) || exit 1 - $(RUSTC) -Copt-level=2 --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs - $(call RUN,test-26235) || exit 1 - $(RUSTC) -Copt-level=3 --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs - $(call RUN,test-26235) || exit 1 - $(RUSTC) -Copt-level=s --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs - $(call RUN,test-26235) || exit 1 - $(RUSTC) -Copt-level=z --emit=llvm-bc,llvm-ir,asm,obj,link test-26235.rs - $(call RUN,test-26235) || exit 1 diff --git a/tests/run-make/emit/rmake.rs b/tests/run-make/emit/rmake.rs new file mode 100644 index 00000000000..8b3ddb66f92 --- /dev/null +++ b/tests/run-make/emit/rmake.rs @@ -0,0 +1,19 @@ +// A bug from 2015 would cause errors when emitting multiple types of files +// in the same rustc call. A fix was created in #30452. This test checks that rustc still compiles +// a source file successfully when emission of multiple output artifacts are requested. +// See https://github.com/rust-lang/rust/pull/30452 + +//@ ignore-cross-compile + +use run_make_support::{run, rustc}; + +fn main() { + let opt_levels = ["0", "1", "2", "3", "s", "z"]; + for level in opt_levels { + rustc().opt_level(level).emit("llvm-bc,llvm-ir,asm,obj,link").input("test-24876.rs").run(); + } + for level in opt_levels { + rustc().opt_level(level).emit("llvm-bc,llvm-ir,asm,obj,link").input("test-26235.rs").run(); + run("test-26235"); + } +} diff --git a/tests/run-make/exit-code/rmake.rs b/tests/run-make/exit-code/rmake.rs index 76d7777581b..f290554831d 100644 --- a/tests/run-make/exit-code/rmake.rs +++ b/tests/run-make/exit-code/rmake.rs @@ -1,25 +1,26 @@ // Test that we exit with the correct exit code for successful / unsuccessful / ICE compilations -use run_make_support::{rustc, rustdoc, tmp_dir}; +use run_make_support::{rustc, rustdoc}; fn main() { rustc().arg("success.rs").run(); - rustc().arg("--invalid-arg-foo").run_fail_assert_exit_code(1); + rustc().arg("--invalid-arg-foo").run_fail().assert_exit_code(1); - rustc().arg("compile-error.rs").run_fail_assert_exit_code(1); + rustc().arg("compile-error.rs").run_fail().assert_exit_code(1); rustc() .env("RUSTC_ICE", "0") .arg("-Ztreat-err-as-bug") .arg("compile-error.rs") - .run_fail_assert_exit_code(101); + .run_fail() + .assert_exit_code(101); - rustdoc().arg("success.rs").output(tmp_dir().join("exit-code")).run(); + rustdoc().arg("success.rs").output("exit-code").run(); - rustdoc().arg("--invalid-arg-foo").run_fail_assert_exit_code(1); + rustdoc().arg("--invalid-arg-foo").run_fail().assert_exit_code(1); - rustdoc().arg("compile-error.rs").run_fail_assert_exit_code(1); + rustdoc().arg("compile-error.rs").run_fail().assert_exit_code(1); - rustdoc().arg("lint-failure.rs").run_fail_assert_exit_code(1); + rustdoc().arg("lint-failure.rs").run_fail().assert_exit_code(1); } diff --git a/tests/run-make/external-crate-panic-handle-no-lint/rmake.rs b/tests/run-make/external-crate-panic-handle-no-lint/rmake.rs index de4023282ef..e54ef53e3dc 100644 --- a/tests/run-make/external-crate-panic-handle-no-lint/rmake.rs +++ b/tests/run-make/external-crate-panic-handle-no-lint/rmake.rs @@ -4,9 +4,9 @@ // and cause the test to fail. // See https://github.com/rust-lang/rust/issues/53964 -use run_make_support::{rustc, tmp_dir}; +use run_make_support::rustc; fn main() { rustc().input("panic.rs").run(); - rustc().input("app.rs").panic("abort").emit("obj").library_search_path(tmp_dir()).run(); + rustc().input("app.rs").panic("abort").emit("obj").run(); } diff --git a/tests/run-make/incr-prev-body-beyond-eof/Makefile b/tests/run-make/incr-prev-body-beyond-eof/Makefile deleted file mode 100644 index aa47552f52c..00000000000 --- a/tests/run-make/incr-prev-body-beyond-eof/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# ignore-none no-std is not supported -# ignore-nvptx64-nvidia-cuda FIXME: can't find crate for `std` - -include ../tools.mk - -# Tests that we don't ICE during incremental compilation after modifying a -# function span such that its previous end line exceeds the number of lines -# in the new file, but its start line/column and length remain the same. - -SRC=$(TMPDIR)/src -INCR=$(TMPDIR)/incr - -all: - mkdir $(SRC) - mkdir $(INCR) - cp a.rs $(SRC)/main.rs - $(RUSTC) -C incremental=$(INCR) $(SRC)/main.rs --target $(TARGET) - cp b.rs $(SRC)/main.rs - $(RUSTC) -C incremental=$(INCR) $(SRC)/main.rs --target $(TARGET) diff --git a/tests/run-make/incr-prev-body-beyond-eof/rmake.rs b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs new file mode 100644 index 00000000000..ccb1f95275e --- /dev/null +++ b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs @@ -0,0 +1,27 @@ +// After modifying the span of a function, if the length of +// the span remained the same but the end line number became different, +// this would cause an internal compiler error (ICE), fixed in #76256. + +// This test compiles main.rs twice, first with end line 16 and +// then with end line 12. If compilation is successful, the end line +// was hashed by rustc in addition to the span length, and the fix still +// works. + +//@ ignore-none +// reason: no-std is not supported + +//@ ignore-nvptx64-nvidia-cuda +// FIXME: can't find crate for `std` + +use run_make_support::rustc; +use std::fs; + +fn main() { + // FIXME(Oneirical): Use run_make_support::fs_wrapper here. + fs::create_dir("src").unwrap(); + fs::create_dir("incr").unwrap(); + fs::copy("a.rs", "src/main.rs").unwrap(); + rustc().incremental("incr").input("src/main.rs").run(); + fs::copy("b.rs", "src/main.rs").unwrap(); + rustc().incremental("incr").input("src/main.rs").run(); +} diff --git a/tests/run-make/issue-107495-archive-permissions/rmake.rs b/tests/run-make/issue-107495-archive-permissions/rmake.rs index db25e9b033c..72ceb10c591 100644 --- a/tests/run-make/issue-107495-archive-permissions/rmake.rs +++ b/tests/run-make/issue-107495-archive-permissions/rmake.rs @@ -3,7 +3,7 @@ #[cfg(unix)] extern crate libc; -use run_make_support::{aux_build, tmp_dir}; +use run_make_support::aux_build; use std::fs; #[cfg(unix)] use std::os::unix::fs::PermissionsExt; @@ -16,7 +16,7 @@ fn main() { } aux_build().arg("foo.rs").run(); - verify(&tmp_dir().join("libfoo.rlib")); + verify(Path::new("libfoo.rlib")); } fn verify(path: &Path) { diff --git a/tests/run-make/issue-125484-used-dependencies/dependency.rs b/tests/run-make/issue-125484-used-dependencies/dependency.rs new file mode 100644 index 00000000000..d15abba5976 --- /dev/null +++ b/tests/run-make/issue-125484-used-dependencies/dependency.rs @@ -0,0 +1 @@ +// Empty diff --git a/tests/run-make/issue-125484-used-dependencies/main.rs b/tests/run-make/issue-125484-used-dependencies/main.rs new file mode 100644 index 00000000000..0c1a1f8208a --- /dev/null +++ b/tests/run-make/issue-125484-used-dependencies/main.rs @@ -0,0 +1,9 @@ +pub type Foo = something::same::Thing; + +mod something { + pub mod same { + pub struct Thing; + } +} + +fn main() {} diff --git a/tests/run-make/issue-125484-used-dependencies/rmake.rs b/tests/run-make/issue-125484-used-dependencies/rmake.rs new file mode 100644 index 00000000000..bc0a18de66e --- /dev/null +++ b/tests/run-make/issue-125484-used-dependencies/rmake.rs @@ -0,0 +1,18 @@ +// Non-regression test for issues #125474, #125484, #125646, with the repro taken from #125484. Some +// queries use "used dependencies" while others use "speculatively loaded dependencies", and an +// indexing ICE appeared in some cases when these were unexpectedly used in the same context. + +// FIXME: this should probably be a UI test instead of a run-make test, but I *cannot* find a way to +// make compiletest annotations reproduce the ICE with the minimizations from issues #125474 and +// #125484. + +use run_make_support::rustc; + +fn main() { + // The dependency is not itself significant, apart from sharing a name with one of main's + // modules. + rustc().crate_name("same").crate_type("rlib").input("dependency.rs").run(); + + // Here, an ICE would happen when building the linker command. + rustc().input("main.rs").extern_("same", "libsame.rlib").run(); +} diff --git a/tests/run-make/issue-84395-lto-embed-bitcode/Makefile b/tests/run-make/issue-84395-lto-embed-bitcode/Makefile index 95c8d08a18b..aabe90754a6 100644 --- a/tests/run-make/issue-84395-lto-embed-bitcode/Makefile +++ b/tests/run-make/issue-84395-lto-embed-bitcode/Makefile @@ -1,4 +1,7 @@ -# needs-matching-clang +# needs-force-clang-based-tests + +# FIXME(#126180): This test doesn't actually run anywhere, because the only +# CI job that sets RUSTBUILD_FORCE_CLANG_BASED_TESTS runs very few tests. # This test makes sure the embed bitcode in elf created with # lto-embed-bitcode=optimized is valid llvm BC module. diff --git a/tests/run-make/issue-88756-default-output/output-default.stdout b/tests/run-make/issue-88756-default-output/output-default.stdout index 12c1b389fb3..bc38d9e9dc6 100644 --- a/tests/run-make/issue-88756-default-output/output-default.stdout +++ b/tests/run-make/issue-88756-default-output/output-default.stdout @@ -157,6 +157,8 @@ Options: Comma separated list of types of output for rustdoc to emit --no-run Compile doctests without running them + --remap-path-prefix FROM=TO + Remap source names in compiler messages --show-type-layout Include the memory layout of types in the docs --nocapture Don't capture stdout and stderr of tests diff --git a/tests/run-make/llvm-outputs/Makefile b/tests/run-make/llvm-outputs/Makefile deleted file mode 100644 index cccf1dd66fb..00000000000 --- a/tests/run-make/llvm-outputs/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -include ../tools.mk - -all: - echo 'fn main() {}' | $(BARE_RUSTC) - --out-dir=$(TMPDIR)/random_directory_that_does_not_exist_ir/ --emit=llvm-ir - echo 'fn main() {}' | $(BARE_RUSTC) - --out-dir=$(TMPDIR)/random_directory_that_does_not_exist_bc/ --emit=llvm-bc diff --git a/tests/run-make/llvm-outputs/rmake.rs b/tests/run-make/llvm-outputs/rmake.rs new file mode 100644 index 00000000000..2dc3030ca91 --- /dev/null +++ b/tests/run-make/llvm-outputs/rmake.rs @@ -0,0 +1,20 @@ +// test that directories get created when emitting llvm bitcode and IR + +use run_make_support::{cwd, run_in_tmpdir, rustc}; +use std::path::PathBuf; + +fn main() { + let mut path_bc = PathBuf::new(); + let mut path_ir = PathBuf::new(); + run_in_tmpdir(|| { + let p = cwd(); + path_bc = p.join("nonexistant_dir_bc"); + path_ir = p.join("nonexistant_dir_ir"); + rustc().input("-").stdin("fn main() {}").out_dir(&path_bc).emit("llvm-bc").run(); + rustc().input("-").stdin("fn main() {}").out_dir(&path_ir).emit("llvm-ir").run(); + assert!(path_bc.exists()); + assert!(path_ir.exists()); + }); + assert!(!path_bc.exists()); + assert!(!path_ir.exists()); +} diff --git a/tests/run-make/manual-crate-name/Makefile b/tests/run-make/manual-crate-name/Makefile deleted file mode 100644 index c00e20c7c57..00000000000 --- a/tests/run-make/manual-crate-name/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) --crate-name foo bar.rs - rm $(TMPDIR)/libfoo.rlib diff --git a/tests/run-make/manual-crate-name/rmake.rs b/tests/run-make/manual-crate-name/rmake.rs new file mode 100644 index 00000000000..f171f78087c --- /dev/null +++ b/tests/run-make/manual-crate-name/rmake.rs @@ -0,0 +1,7 @@ +use run_make_support::rustc; +use std::path::Path; + +fn main() { + rustc().input("bar.rs").crate_name("foo").run(); + assert!(Path::new("libfoo.rlib").is_file()); +} diff --git a/tests/run-make/mixing-formats/Makefile b/tests/run-make/mixing-formats/Makefile deleted file mode 100644 index d01978a1599..00000000000 --- a/tests/run-make/mixing-formats/Makefile +++ /dev/null @@ -1,75 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# Testing various mixings of rlibs and dylibs. Makes sure that it's possible to -# link an rlib to a dylib. The dependency tree among the file looks like: -# -# foo -# / \ -# bar1 bar2 -# / \ / -# baz baz2 -# -# This is generally testing the permutations of the foo/bar1/bar2 layer against -# the baz/baz2 layer - -all: - # Building just baz - $(RUSTC) --crate-type=rlib foo.rs - $(RUSTC) --crate-type=dylib bar1.rs -C prefer-dynamic - $(RUSTC) --crate-type=dylib,rlib baz.rs -C prefer-dynamic - $(RUSTC) --crate-type=bin baz.rs - rm $(TMPDIR)/* - $(RUSTC) --crate-type=dylib foo.rs -C prefer-dynamic - $(RUSTC) --crate-type=rlib bar1.rs - $(RUSTC) --crate-type=dylib,rlib baz.rs -C prefer-dynamic - $(RUSTC) --crate-type=bin baz.rs - rm $(TMPDIR)/* - # Building baz2 - $(RUSTC) --crate-type=rlib foo.rs - $(RUSTC) --crate-type=dylib bar1.rs -C prefer-dynamic - $(RUSTC) --crate-type=dylib bar2.rs -C prefer-dynamic - $(RUSTC) --crate-type=dylib baz2.rs && exit 1 || exit 0 - $(RUSTC) --crate-type=bin baz2.rs && exit 1 || exit 0 - rm $(TMPDIR)/* - $(RUSTC) --crate-type=rlib foo.rs - $(RUSTC) --crate-type=rlib bar1.rs - $(RUSTC) --crate-type=dylib bar2.rs -C prefer-dynamic - $(RUSTC) --crate-type=dylib,rlib baz2.rs - $(RUSTC) --crate-type=bin baz2.rs - rm $(TMPDIR)/* - $(RUSTC) --crate-type=rlib foo.rs - $(RUSTC) --crate-type=dylib bar1.rs -C prefer-dynamic - $(RUSTC) --crate-type=rlib bar2.rs - $(RUSTC) --crate-type=dylib,rlib baz2.rs -C prefer-dynamic - $(RUSTC) --crate-type=bin baz2.rs - rm $(TMPDIR)/* - $(RUSTC) --crate-type=rlib foo.rs - $(RUSTC) --crate-type=rlib bar1.rs - $(RUSTC) --crate-type=rlib bar2.rs - $(RUSTC) --crate-type=dylib,rlib baz2.rs -C prefer-dynamic - $(RUSTC) --crate-type=bin baz2.rs - rm $(TMPDIR)/* - $(RUSTC) --crate-type=dylib foo.rs -C prefer-dynamic - $(RUSTC) --crate-type=rlib bar1.rs - $(RUSTC) --crate-type=rlib bar2.rs - $(RUSTC) --crate-type=dylib,rlib baz2.rs -C prefer-dynamic - $(RUSTC) --crate-type=bin baz2.rs - rm $(TMPDIR)/* - $(RUSTC) --crate-type=dylib foo.rs -C prefer-dynamic - $(RUSTC) --crate-type=dylib bar1.rs -C prefer-dynamic - $(RUSTC) --crate-type=rlib bar2.rs - $(RUSTC) --crate-type=dylib,rlib baz2.rs - $(RUSTC) --crate-type=bin baz2.rs - rm $(TMPDIR)/* - $(RUSTC) --crate-type=dylib foo.rs -C prefer-dynamic - $(RUSTC) --crate-type=rlib bar1.rs - $(RUSTC) --crate-type=dylib bar2.rs -C prefer-dynamic - $(RUSTC) --crate-type=dylib,rlib baz2.rs - $(RUSTC) --crate-type=bin baz2.rs - rm $(TMPDIR)/* - $(RUSTC) --crate-type=dylib foo.rs -C prefer-dynamic - $(RUSTC) --crate-type=dylib bar1.rs -C prefer-dynamic - $(RUSTC) --crate-type=dylib bar2.rs -C prefer-dynamic - $(RUSTC) --crate-type=dylib,rlib baz2.rs - $(RUSTC) --crate-type=bin baz2.rs diff --git a/tests/run-make/mixing-formats/rmake.rs b/tests/run-make/mixing-formats/rmake.rs new file mode 100644 index 00000000000..9cbff94f670 --- /dev/null +++ b/tests/run-make/mixing-formats/rmake.rs @@ -0,0 +1,87 @@ +// Testing various mixings of rlibs and dylibs. Makes sure that it's possible to +// link an rlib to a dylib. The dependency tree among the file looks like: +// +// foo +// / \ +// bar1 bar2 +// / \ / +// baz baz2 +// +// This is generally testing the permutations of the foo/bar1/bar2 layer against +// the baz/baz2 layer + +//@ ignore-cross-compile + +use run_make_support::{run_in_tmpdir, rustc}; +use std::fs; + +fn main() { + run_in_tmpdir(|| { + // Building just baz + rustc().crate_type("rlib").input("foo.rs").run(); + rustc().crate_type("dylib").input("bar1.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("dylib,rlib").input("baz.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("bin").input("baz.rs").run(); + }); + run_in_tmpdir(|| { + rustc().crate_type("dylib").input("foo.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("rlib").input("bar1.rs").run(); + rustc().crate_type("dylib,rlib").input("baz.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("bin").input("baz.rs").run(); + }); + run_in_tmpdir(|| { + // Building baz2 + rustc().crate_type("rlib").input("foo.rs").run(); + rustc().crate_type("dylib").input("bar1.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("dylib").input("bar2.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("dylib").input("baz2.rs").run_fail().assert_exit_code(1); + rustc().crate_type("bin").input("baz2.rs").run_fail().assert_exit_code(1); + }); + run_in_tmpdir(|| { + rustc().crate_type("rlib").input("foo.rs").run(); + rustc().crate_type("rlib").input("bar1.rs").run(); + rustc().crate_type("dylib").input("bar2.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("dylib,rlib").input("baz2.rs").run(); + rustc().crate_type("bin").input("baz2.rs").run(); + }); + run_in_tmpdir(|| { + rustc().crate_type("rlib").input("foo.rs").run(); + rustc().crate_type("dylib").input("bar1.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("rlib").input("bar2.rs").run(); + rustc().crate_type("dylib,rlib").input("baz2.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("bin").input("baz2.rs").run(); + }); + run_in_tmpdir(|| { + rustc().crate_type("rlib").input("foo.rs").run(); + rustc().crate_type("rlib").input("bar1.rs").run(); + rustc().crate_type("rlib").input("bar2.rs").run(); + rustc().crate_type("dylib,rlib").input("baz2.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("bin").input("baz2.rs").run(); + }); + run_in_tmpdir(|| { + rustc().crate_type("dylib").input("foo.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("rlib").input("bar1.rs").run(); + rustc().crate_type("rlib").input("bar2.rs").run(); + rustc().crate_type("dylib,rlib").input("baz2.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("bin").input("baz2.rs").run(); + }); + run_in_tmpdir(|| { + rustc().crate_type("dylib").input("foo.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("dylib").input("bar1.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("rlib").input("bar2.rs").run(); + rustc().crate_type("dylib,rlib").input("baz2.rs").run(); + rustc().crate_type("bin").input("baz2.rs").run(); + }); + run_in_tmpdir(|| { + rustc().crate_type("dylib").input("foo.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("rlib").input("bar1.rs").run(); + rustc().crate_type("dylib").input("bar2.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("dylib,rlib").input("baz2.rs").run(); + rustc().crate_type("bin").input("baz2.rs").run(); + }); + rustc().crate_type("dylib").input("foo.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("dylib").input("bar1.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("dylib").input("bar2.rs").arg("-Cprefer-dynamic").run(); + rustc().crate_type("dylib,rlib").input("baz2.rs").run(); + rustc().crate_type("bin").input("baz2.rs").run(); +} diff --git a/tests/run-make/multiple-emits/Makefile b/tests/run-make/multiple-emits/Makefile deleted file mode 100644 index d1f29764485..00000000000 --- a/tests/run-make/multiple-emits/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) foo.rs --emit=asm,llvm-ir -o $(TMPDIR)/out 2>&1 - rm $(TMPDIR)/out.ll $(TMPDIR)/out.s - $(RUSTC) foo.rs --emit=asm,llvm-ir -o $(TMPDIR)/out2.ext 2>&1 - rm $(TMPDIR)/out2.ll $(TMPDIR)/out2.s diff --git a/tests/run-make/multiple-emits/rmake.rs b/tests/run-make/multiple-emits/rmake.rs new file mode 100644 index 00000000000..67c0ebb9864 --- /dev/null +++ b/tests/run-make/multiple-emits/rmake.rs @@ -0,0 +1,13 @@ +use run_make_support::{cwd, path, rustc}; + +fn main() { + rustc().input("foo.rs").emit("asm,llvm-ir").output("out").run(); + + assert!(path("out.ll").is_file()); + assert!(path("out.s").is_file()); + + rustc().input("foo.rs").emit("asm,llvm-ir").output("out2.ext").run(); + + assert!(path("out2.ll").is_file()); + assert!(path("out2.s").is_file()); +} diff --git a/tests/run-make/no-input-file/no-input-file.stderr b/tests/run-make/no-input-file/no-input-file.stderr deleted file mode 100644 index b843eb524f3..00000000000 --- a/tests/run-make/no-input-file/no-input-file.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: no input filename given - diff --git a/tests/run-make/no-input-file/rmake.rs b/tests/run-make/no-input-file/rmake.rs index 15e582311f0..fc558b22fb4 100644 --- a/tests/run-make/no-input-file/rmake.rs +++ b/tests/run-make/no-input-file/rmake.rs @@ -1,7 +1,9 @@ -use run_make_support::{diff, rustc}; +use run_make_support::rustc; fn main() { - let output = rustc().print("crate-name").run_fail_assert_exit_code(1); - - diff().expected_file("no-input-file.stderr").actual_text("output", output.stderr).run(); + rustc() + .print("crate-name") + .run_fail() + .assert_exit_code(1) + .assert_stderr_equals("error: no input filename given"); } diff --git a/tests/run-make/no-intermediate-extras/rmake.rs b/tests/run-make/no-intermediate-extras/rmake.rs index 19479e3bd5b..0641417504e 100644 --- a/tests/run-make/no-intermediate-extras/rmake.rs +++ b/tests/run-make/no-intermediate-extras/rmake.rs @@ -5,13 +5,13 @@ //@ ignore-cross-compile -use run_make_support::{rustc, tmp_dir}; +use run_make_support::rustc; use std::fs; fn main() { rustc().crate_type("rlib").arg("--test").input("foo.rs").run(); assert!( - fs::remove_file(tmp_dir().join("foo.bc")).is_err(), + fs::remove_file("foo.bc").is_err(), "An unwanted .bc file was created by run-make/no-intermediate-extras." ); } diff --git a/tests/run-make/non-pie-thread-local/rmake.rs b/tests/run-make/non-pie-thread-local/rmake.rs index 1ef447e7860..1758f1a0855 100644 --- a/tests/run-make/non-pie-thread-local/rmake.rs +++ b/tests/run-make/non-pie-thread-local/rmake.rs @@ -7,13 +7,13 @@ //@ ignore-cross-compile //@ only-linux -use run_make_support::{cc, run, rustc, tmp_dir}; +use run_make_support::{cc, cwd, run, rustc}; fn main() { rustc().input("foo.rs").run(); cc().input("foo.c") .arg("-lfoo") - .library_search_path(tmp_dir()) + .library_search_path(cwd()) .arg("-Wl,--gc-sections") .arg("-lpthread") .arg("-ldl") @@ -22,7 +22,7 @@ fn main() { run("foo"); cc().input("foo.c") .arg("-lfoo") - .library_search_path(tmp_dir()) + .library_search_path(cwd()) .arg("-Wl,--gc-sections") .arg("-lpthread") .arg("-ldl") diff --git a/tests/run-make/non-unicode-env/rmake.rs b/tests/run-make/non-unicode-env/rmake.rs index a4843a52efd..ed40d7a6d7f 100644 --- a/tests/run-make/non-unicode-env/rmake.rs +++ b/tests/run-make/non-unicode-env/rmake.rs @@ -6,7 +6,6 @@ fn main() { #[cfg(windows)] let non_unicode: std::ffi::OsString = std::os::windows::ffi::OsStringExt::from_wide(&[0xD800]); let output = rustc().input("non_unicode_env.rs").env("NON_UNICODE_VAR", non_unicode).run_fail(); - let actual = std::str::from_utf8(&output.stderr).unwrap(); let expected = std::fs::read_to_string("non_unicode_env.stderr").unwrap(); - assert_eq!(actual, expected); + output.assert_stderr_equals(expected); } diff --git a/tests/run-make/non-unicode-in-incremental-dir/rmake.rs b/tests/run-make/non-unicode-in-incremental-dir/rmake.rs index 40152e0411d..ba1bd448743 100644 --- a/tests/run-make/non-unicode-in-incremental-dir/rmake.rs +++ b/tests/run-make/non-unicode-in-incremental-dir/rmake.rs @@ -1,21 +1,21 @@ -use run_make_support::{rustc, tmp_dir}; +use run_make_support::rustc; fn main() { #[cfg(unix)] let non_unicode: &std::ffi::OsStr = std::os::unix::ffi::OsStrExt::from_bytes(&[0xFF]); #[cfg(windows)] let non_unicode: std::ffi::OsString = std::os::windows::ffi::OsStringExt::from_wide(&[0xD800]); - match std::fs::create_dir(tmp_dir().join(&non_unicode)) { + match std::fs::create_dir(&non_unicode) { // If an error occurs, check if creating a directory with a valid Unicode name would // succeed. - Err(e) if std::fs::create_dir(tmp_dir().join("valid_unicode")).is_ok() => { + Err(e) if std::fs::create_dir("valid_unicode").is_ok() => { // Filesystem doesn't appear support non-Unicode paths. return; } Err(e) => panic!("error creating non-Unicode directory: {e}"), _ => {} } - let incr_dir = tmp_dir().join("incr-dir"); + let incr_dir = "incr-dir"; rustc().input("foo.rs").incremental(&incr_dir).run(); for crate_dir in std::fs::read_dir(&incr_dir).unwrap() { std::fs::create_dir(crate_dir.unwrap().path().join(&non_unicode)).unwrap(); diff --git a/tests/run-make/notify-all-emit-artifacts/lib.rs b/tests/run-make/notify-all-emit-artifacts/lib.rs new file mode 100644 index 00000000000..6ed194204b4 --- /dev/null +++ b/tests/run-make/notify-all-emit-artifacts/lib.rs @@ -0,0 +1,21 @@ +fn one() -> usize { + 1 +} + +pub mod a { + pub fn two() -> usize { + ::one() + ::one() + } +} + +pub mod b { + pub fn three() -> usize { + ::one() + ::a::two() + } +} + +#[inline(never)] +pub fn main() { + a::two(); + b::three(); +} diff --git a/tests/run-make/notify-all-emit-artifacts/rmake.rs b/tests/run-make/notify-all-emit-artifacts/rmake.rs new file mode 100644 index 00000000000..321eda48941 --- /dev/null +++ b/tests/run-make/notify-all-emit-artifacts/rmake.rs @@ -0,0 +1,43 @@ +// rust should produce artifact notifications about files it was asked to --emit. +// +// It should work in incremental mode both on the first pass where files are generated as well +// as on subsequent passes where they are taken from the incremental cache +// +// See <https://internals.rust-lang.org/t/easier-access-to-files-generated-by-emit-foo/20477> +extern crate run_make_support; + +use run_make_support::{cwd, rustc}; + +fn main() { + // With single codegen unit files are renamed to match the source file name + for _ in 0..=1 { + let output = rustc() + .input("lib.rs") + .emit("obj,asm,llvm-ir,llvm-bc,mir") + .codegen_units(1) + .json("artifacts") + .error_format("json") + .incremental(cwd()) + .run(); + let stderr = output.stderr_utf8(); + for file in &["lib.o", "lib.ll", "lib.bc", "lib.s"] { + assert!(stderr.contains(file), "No {:?} in {:?}", file, stderr); + } + } + + // with multiple codegen units files keep codegen unit id part. + for _ in 0..=1 { + let output = rustc() + .input("lib.rs") + .emit("obj,asm,llvm-ir,llvm-bc,mir") + .codegen_units(2) + .json("artifacts") + .error_format("json") + .incremental(cwd()) + .run(); + let stderr = output.stderr_utf8(); + for file in &["rcgu.o", "rcgu.ll", "rcgu.bc", "rcgu.s"] { + assert!(stderr.contains(file), "No {:?} in {:?}", file, stderr); + } + } +} diff --git a/tests/run-make/panic-impl-transitive/rmake.rs b/tests/run-make/panic-impl-transitive/rmake.rs index 86308f593b3..c09b233b23e 100644 --- a/tests/run-make/panic-impl-transitive/rmake.rs +++ b/tests/run-make/panic-impl-transitive/rmake.rs @@ -6,14 +6,9 @@ // function in the crate. // See https://github.com/rust-lang/rust/pull/50338 -use run_make_support::{rustc, tmp_dir}; +use run_make_support::rustc; fn main() { rustc().input("panic-impl-provider.rs").run(); - rustc() - .input("panic-impl-consumer.rs") - .panic("abort") - .emit("llvm-ir") - .library_search_path(tmp_dir()) - .run(); + rustc().input("panic-impl-consumer.rs").panic("abort").emit("llvm-ir").run(); } diff --git a/tests/run-make/print-cfg/rmake.rs b/tests/run-make/print-cfg/rmake.rs index 6e72c16f1f9..f382d952db4 100644 --- a/tests/run-make/print-cfg/rmake.rs +++ b/tests/run-make/print-cfg/rmake.rs @@ -7,10 +7,10 @@ use std::collections::HashSet; use std::ffi::OsString; -use std::io::BufRead; use std::iter::FromIterator; +use std::path::PathBuf; -use run_make_support::{rustc, tmp_dir}; +use run_make_support::rustc; struct PrintCfg { target: &'static str, @@ -83,19 +83,18 @@ fn check(PrintCfg { target, includes, disallow }: PrintCfg) { // --print=cfg { let output = rustc().target(target).print("cfg").run(); - - let stdout = String::from_utf8(output.stdout).unwrap(); + let stdout = output.stdout_utf8(); check_(&stdout, includes, disallow); } // --print=cfg=PATH { - let tmp_path = tmp_dir().join(format!("{target}.cfg")); + let tmp_path = PathBuf::from(format!("{target}.cfg")); let mut print_arg = OsString::from("--print=cfg="); print_arg.push(tmp_path.as_os_str()); - let output = rustc().target(target).arg(print_arg).run(); + rustc().target(target).arg(print_arg).run(); let output = std::fs::read_to_string(&tmp_path).unwrap(); diff --git a/tests/run-make/print-check-cfg/rmake.rs b/tests/run-make/print-check-cfg/rmake.rs index 2d522164426..f4b02b5e265 100644 --- a/tests/run-make/print-check-cfg/rmake.rs +++ b/tests/run-make/print-check-cfg/rmake.rs @@ -49,6 +49,20 @@ fn main() { }, }); check(CheckCfg { + args: &["--check-cfg=cfg(feature, values())"], + contains: Contains::Some { + contains: &["feature="], + doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature"], + }, + }); + check(CheckCfg { + args: &["--check-cfg=cfg(feature, values())", "--check-cfg=cfg(feature, values(none()))"], + contains: Contains::Some { + contains: &["feature"], + doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature="], + }, + }); + check(CheckCfg { args: &[ r#"--check-cfg=cfg(feature, values(any()))"#, r#"--check-cfg=cfg(feature, values("tmp"))"#, @@ -79,7 +93,7 @@ fn check(CheckCfg { args, contains }: CheckCfg) { .args(&*args) .run(); - let stdout = String::from_utf8(output.stdout).unwrap(); + let stdout = output.stdout_utf8(); let mut found = HashSet::<String>::new(); diff --git a/tests/run-make/print-native-static-libs/rmake.rs b/tests/run-make/print-native-static-libs/rmake.rs index edb85d568c6..b4e7c0e17ff 100644 --- a/tests/run-make/print-native-static-libs/rmake.rs +++ b/tests/run-make/print-native-static-libs/rmake.rs @@ -30,9 +30,7 @@ fn main() { .run(); let mut found_note = false; - for l in output.stderr.lines() { - let l = l.expect("utf-8 string"); - + for l in output.stderr_utf8().lines() { let Some(args) = l.strip_prefix("note: native-static-libs:") else { continue; }; diff --git a/tests/run-make/print-to-output/rmake.rs b/tests/run-make/print-to-output/rmake.rs index 1763cd378d2..ff5e6cacf4f 100644 --- a/tests/run-make/print-to-output/rmake.rs +++ b/tests/run-make/print-to-output/rmake.rs @@ -2,8 +2,9 @@ //! output to a file (instead of stdout) use std::ffi::OsString; +use std::path::PathBuf; -use run_make_support::{rustc, target, tmp_dir}; +use run_make_support::{rustc, target}; struct Option<'a> { target: &'a str, @@ -38,19 +39,15 @@ fn check(args: Option) { } // --print={option} - let stdout = { - let output = rustc().target(args.target).print(args.option).run(); - - String::from_utf8(output.stdout).unwrap() - }; + let stdout = rustc().target(args.target).print(args.option).run().stdout_utf8(); // --print={option}=PATH let output = { - let tmp_path = tmp_dir().join(format!("{}.txt", args.option)); + let tmp_path = PathBuf::from(format!("{}.txt", args.option)); let mut print_arg = OsString::from(format!("--print={}=", args.option)); print_arg.push(tmp_path.as_os_str()); - let _output = rustc().target(args.target).arg(print_arg).run(); + rustc().target(args.target).arg(print_arg).run(); std::fs::read_to_string(&tmp_path).unwrap() }; diff --git a/tests/run-make/reachable-extern-fn-available-lto/rmake.rs b/tests/run-make/reachable-extern-fn-available-lto/rmake.rs index c7262b9461b..558444846fd 100644 --- a/tests/run-make/reachable-extern-fn-available-lto/rmake.rs +++ b/tests/run-make/reachable-extern-fn-available-lto/rmake.rs @@ -9,10 +9,10 @@ //@ ignore-cross-compile -use run_make_support::{cc, extra_c_flags, run, rustc, static_lib}; +use run_make_support::{cc, extra_c_flags, run, rustc, static_lib_name}; fn main() { - let libbar_path = static_lib("bar"); + let libbar_path = static_lib_name("bar"); rustc().input("foo.rs").crate_type("rlib").run(); rustc() .input("bar.rs") diff --git a/tests/run-make/repr128-dwarf/rmake.rs b/tests/run-make/repr128-dwarf/rmake.rs index fd5dd810444..27e32099396 100644 --- a/tests/run-make/repr128-dwarf/rmake.rs +++ b/tests/run-make/repr128-dwarf/rmake.rs @@ -1,15 +1,15 @@ //@ ignore-windows // This test should be replaced with one in tests/debuginfo once GDB or LLDB support 128-bit enums. -use gimli::{AttributeValue, Dwarf, EndianRcSlice, Reader, RunTimeEndian}; +use gimli::{AttributeValue, EndianRcSlice, Reader, RunTimeEndian}; use object::{Object, ObjectSection}; -use run_make_support::{gimli, object, rustc, tmp_dir}; -use std::borrow::Cow; +use run_make_support::{gimli, object, rustc}; use std::collections::HashMap; +use std::path::PathBuf; use std::rc::Rc; fn main() { - let output = tmp_dir().join("repr128"); + let output = PathBuf::from("repr128"); rustc().input("main.rs").output(&output).arg("-Cdebuginfo=2").run(); // Mach-O uses packed debug info let dsym_location = output diff --git a/tests/run-make/reset-codegen-1/rmake.rs b/tests/run-make/reset-codegen-1/rmake.rs index 4b91ba7df90..c1385b2e015 100644 --- a/tests/run-make/reset-codegen-1/rmake.rs +++ b/tests/run-make/reset-codegen-1/rmake.rs @@ -7,12 +7,12 @@ //@ ignore-cross-compile -use run_make_support::{rustc, tmp_dir}; +use run_make_support::rustc; use std::fs; fn compile(output_file: &str, emit: Option<&str>) { let mut rustc = rustc(); - let rustc = rustc.codegen_units(4).output(tmp_dir().join(output_file)).input("foo.rs"); + let rustc = rustc.codegen_units(4).output(output_file).input("foo.rs"); if let Some(emit) = emit { rustc.emit(emit); } diff --git a/tests/run-make/resolve-rename/Makefile b/tests/run-make/resolve-rename/Makefile deleted file mode 100644 index 00f83a5d6b2..00000000000 --- a/tests/run-make/resolve-rename/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) -C extra-filename=-hash foo.rs - $(RUSTC) bar.rs - mv $(TMPDIR)/libfoo-hash.rlib $(TMPDIR)/libfoo-another-hash.rlib - $(RUSTC) baz.rs diff --git a/tests/run-make/resolve-rename/rmake.rs b/tests/run-make/resolve-rename/rmake.rs new file mode 100644 index 00000000000..a5f48c2bbcc --- /dev/null +++ b/tests/run-make/resolve-rename/rmake.rs @@ -0,0 +1,15 @@ +// If a library is compiled with -C extra-filename, the rust compiler +// will take this into account when searching for libraries. However, +// if that library is then renamed, the rust compiler should fall back +// to its regular library location logic and not immediately fail to find +// the renamed library. +// See https://github.com/rust-lang/rust/pull/49253 + +use run_make_support::rustc; +use std::fs; +fn main() { + rustc().extra_filename("-hash").input("foo.rs").run(); + rustc().input("bar.rs").run(); + fs::rename("libfoo-hash.rlib", "libfoo-another-hash.rlib").unwrap(); + rustc().input("baz.rs").run(); +} diff --git a/tests/run-make/run-in-tmpdir-self-test/rmake.rs b/tests/run-make/run-in-tmpdir-self-test/rmake.rs new file mode 100644 index 00000000000..83b99bfe863 --- /dev/null +++ b/tests/run-make/run-in-tmpdir-self-test/rmake.rs @@ -0,0 +1,38 @@ +//! This is a self-test for the `run_in_tmpdir` helper in the support library. This test tries to +//! check that files and directories created within the temporary directory gets properly cleared +//! when returning from the closure. + +use std::fs; +use std::path::{Path, PathBuf}; + +use run_make_support::{cwd, run_in_tmpdir}; + +fn main() { + let mut file_path = PathBuf::new(); + let mut dir_path = PathBuf::new(); + let mut readonly_file_path = PathBuf::new(); + let test_cwd = cwd(); + run_in_tmpdir(|| { + assert_ne!(test_cwd, cwd(), "test cwd should not be the same as tmpdir cwd"); + + file_path = cwd().join("foo.txt"); + fs::write(&file_path, "hi").unwrap(); + + dir_path = cwd().join("bar"); + fs::create_dir_all(&dir_path).unwrap(); + + readonly_file_path = cwd().join("readonly-file.txt"); + fs::write(&readonly_file_path, "owo").unwrap(); + let mut perms = fs::metadata(&readonly_file_path).unwrap().permissions(); + perms.set_readonly(true); + fs::set_permissions(&mut readonly_file_path, perms).unwrap(); + + assert!(file_path.exists()); + assert!(dir_path.exists()); + assert!(readonly_file_path.exists()); + }); + assert!(!file_path.exists()); + assert!(!dir_path.exists()); + assert!(!readonly_file_path.exists()); + assert_eq!(test_cwd, cwd(), "test cwd is not correctly restored"); +} diff --git a/tests/run-make/rust-lld-by-default/rmake.rs b/tests/run-make/rust-lld-by-default/rmake.rs index 8ab16394a91..5b065f86f53 100644 --- a/tests/run-make/rust-lld-by-default/rmake.rs +++ b/tests/run-make/rust-lld-by-default/rmake.rs @@ -17,9 +17,9 @@ fn main() { .input("main.rs") .run(); assert!( - find_lld_version_in_logs(&output), + find_lld_version_in_logs(output.stderr_utf8()), "the LLD version string should be present in the output logs:\n{}", - std::str::from_utf8(&output.stderr).unwrap() + output.stderr_utf8() ); // But it can still be disabled by turning the linker feature off. @@ -30,14 +30,13 @@ fn main() { .input("main.rs") .run(); assert!( - !find_lld_version_in_logs(&output), + !find_lld_version_in_logs(output.stderr_utf8()), "the LLD version string should not be present in the output logs:\n{}", - std::str::from_utf8(&output.stderr).unwrap() + output.stderr_utf8() ); } -fn find_lld_version_in_logs(output: &Output) -> bool { +fn find_lld_version_in_logs(stderr: String) -> bool { let lld_version_re = Regex::new(r"^LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap(); - let stderr = std::str::from_utf8(&output.stderr).unwrap(); stderr.lines().any(|line| lld_version_re.is_match(line.trim())) } diff --git a/tests/run-make/rust-lld-custom-target/rmake.rs b/tests/run-make/rust-lld-custom-target/rmake.rs index e6c4a321d00..f3dc2275f62 100644 --- a/tests/run-make/rust-lld-custom-target/rmake.rs +++ b/tests/run-make/rust-lld-custom-target/rmake.rs @@ -23,9 +23,9 @@ fn main() { .input("lib.rs") .run(); assert!( - find_lld_version_in_logs(&output), + find_lld_version_in_logs(output.stderr_utf8()), "the LLD version string should be present in the output logs:\n{}", - std::str::from_utf8(&output.stderr).unwrap() + output.stderr_utf8() ); // But it can also be disabled via linker features. @@ -38,14 +38,13 @@ fn main() { .input("lib.rs") .run(); assert!( - !find_lld_version_in_logs(&output), + !find_lld_version_in_logs(output.stderr_utf8()), "the LLD version string should not be present in the output logs:\n{}", - std::str::from_utf8(&output.stderr).unwrap() + output.stderr_utf8() ); } -fn find_lld_version_in_logs(output: &Output) -> bool { +fn find_lld_version_in_logs(stderr: String) -> bool { let lld_version_re = Regex::new(r"^LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap(); - let stderr = std::str::from_utf8(&output.stderr).unwrap(); stderr.lines().any(|line| lld_version_re.is_match(line.trim())) } diff --git a/tests/run-make/rust-lld/rmake.rs b/tests/run-make/rust-lld/rmake.rs index a74e858045d..3eb60367c7f 100644 --- a/tests/run-make/rust-lld/rmake.rs +++ b/tests/run-make/rust-lld/rmake.rs @@ -21,9 +21,9 @@ fn main() { .input("main.rs") .run(); assert!( - find_lld_version_in_logs(&output), + find_lld_version_in_logs(output.stderr_utf8()), "the LLD version string should be present in the output logs:\n{}", - std::str::from_utf8(&output.stderr).unwrap() + output.stderr_utf8() ); // It should not be used when we explictly opt-out of lld. @@ -34,9 +34,9 @@ fn main() { .input("main.rs") .run(); assert!( - !find_lld_version_in_logs(&output), + !find_lld_version_in_logs(output.stderr_utf8()), "the LLD version string should not be present in the output logs:\n{}", - std::str::from_utf8(&output.stderr).unwrap() + output.stderr_utf8() ); // While we're here, also check that the last linker feature flag "wins" when passed multiple @@ -52,14 +52,13 @@ fn main() { .input("main.rs") .run(); assert!( - find_lld_version_in_logs(&output), + find_lld_version_in_logs(output.stderr_utf8()), "the LLD version string should be present in the output logs:\n{}", - std::str::from_utf8(&output.stderr).unwrap() + output.stderr_utf8() ); } -fn find_lld_version_in_logs(output: &Output) -> bool { +fn find_lld_version_in_logs(stderr: String) -> bool { let lld_version_re = Regex::new(r"^LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap(); - let stderr = std::str::from_utf8(&output.stderr).unwrap(); stderr.lines().any(|line| lld_version_re.is_match(line.trim())) } diff --git a/tests/run-make/rustdoc-determinism/rmake.rs b/tests/run-make/rustdoc-determinism/rmake.rs index 09097d4507d..2d4f357d681 100644 --- a/tests/run-make/rustdoc-determinism/rmake.rs +++ b/tests/run-make/rustdoc-determinism/rmake.rs @@ -1,14 +1,15 @@ // 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}; +use run_make_support::{diff, rustdoc}; +use std::path::Path; fn main() { - let foo_first = tmp_dir().join("foo_first"); + let foo_first = Path::new("foo_first"); rustdoc().input("foo.rs").output(&foo_first).run(); rustdoc().input("bar.rs").output(&foo_first).run(); - let bar_first = tmp_dir().join("bar_first"); + let bar_first = Path::new("bar_first"); rustdoc().input("bar.rs").output(&bar_first).run(); rustdoc().input("foo.rs").output(&bar_first).run(); diff --git a/tests/run-make/rustdoc-error-lines/rmake.rs b/tests/run-make/rustdoc-error-lines/rmake.rs index db6e28e4feb..ea5ec2faed9 100644 --- a/tests/run-make/rustdoc-error-lines/rmake.rs +++ b/tests/run-make/rustdoc-error-lines/rmake.rs @@ -4,9 +4,7 @@ use run_make_support::rustdoc; fn main() { - let output = - String::from_utf8(rustdoc().input("input.rs").arg("--test").command_output().stdout) - .unwrap(); + let output = rustdoc().input("input.rs").arg("--test").run_fail().stdout_utf8(); let should_contain = &[ "input.rs - foo (line 5)", diff --git a/tests/run-make/rustdoc-map-file/rmake.rs b/tests/run-make/rustdoc-map-file/rmake.rs index d017b41bcdd..de75561c9fb 100644 --- a/tests/run-make/rustdoc-map-file/rmake.rs +++ b/tests/run-make/rustdoc-map-file/rmake.rs @@ -1,7 +1,7 @@ -use run_make_support::{python_command, rustdoc, tmp_dir}; +use run_make_support::{python_command, rustdoc}; fn main() { - let out_dir = tmp_dir().join("out"); + let out_dir = "out"; rustdoc() .input("foo.rs") .arg("-Zunstable-options") diff --git a/tests/run-make/rustdoc-output-path/rmake.rs b/tests/run-make/rustdoc-output-path/rmake.rs index 74fb0a56ac6..28e0fd98f93 100644 --- a/tests/run-make/rustdoc-output-path/rmake.rs +++ b/tests/run-make/rustdoc-output-path/rmake.rs @@ -1,9 +1,10 @@ // Checks that if the output folder doesn't exist, rustdoc will create it. -use run_make_support::{rustdoc, tmp_dir}; +use run_make_support::rustdoc; +use std::path::Path; fn main() { - let out_dir = tmp_dir().join("foo/bar/doc"); + let out_dir = Path::new("foo/bar/doc"); rustdoc().input("foo.rs").output(&out_dir).run(); assert!(out_dir.exists()); } diff --git a/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs b/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs index 81b7defafc6..c9650def347 100644 --- a/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs +++ b/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs @@ -1,25 +1,21 @@ //@ ignore-cross-compile -use run_make_support::{htmldocck, rustc, rustdoc, tmp_dir}; +use run_make_support::{htmldocck, rust_lib_name, rustc, rustdoc}; fn main() { - let tmp_dir = tmp_dir(); - let out_dir = tmp_dir.join("rustdoc"); - let ex_dir = tmp_dir.join("ex.calls"); + let out_dir = "rustdoc"; + let ex_dir = "ex.calls"; let proc_crate_name = "foobar_macro"; let crate_name = "foobar"; - let dylib_name = String::from_utf8( - rustc() - .crate_name(proc_crate_name) - .crate_type("dylib") - .arg("--print") - .arg("file-names") - .arg("-") - .command_output() - .stdout, - ) - .unwrap(); + let dylib_name = rustc() + .crate_name(proc_crate_name) + .crate_type("dylib") + .arg("--print") + .arg("file-names") + .arg("-") + .run() + .stdout_utf8(); rustc() .input("src/proc.rs") @@ -41,8 +37,8 @@ fn main() { .crate_name("ex") .crate_type("bin") .output(&out_dir) - .extern_(crate_name, tmp_dir.join(format!("lib{crate_name}.rlib"))) - .extern_(proc_crate_name, tmp_dir.join(dylib_name.trim())) + .extern_(crate_name, rust_lib_name(crate_name)) + .extern_(proc_crate_name, dylib_name.trim()) .arg("-Zunstable-options") .arg("--scrape-examples-output-path") .arg(&ex_dir) diff --git a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs index 563e3aca9ae..41efb837458 100644 --- a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs +++ b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs @@ -1,10 +1,9 @@ -use run_make_support::{htmldocck, rustc, rustdoc, source_path, tmp_dir}; +use run_make_support::{htmldocck, rustc, rustdoc, source_root}; use std::fs::read_dir; use std::path::Path; pub fn scrape(extra_args: &[&str]) { - let lib_dir = tmp_dir(); - let out_dir = tmp_dir().join("rustdoc"); + let out_dir = Path::new("rustdoc"); let crate_name = "foobar"; let deps = read_dir("examples") .unwrap() @@ -23,7 +22,7 @@ pub fn scrape(extra_args: &[&str]) { .crate_name(&dep_stem) .crate_type("bin") .output(&out_dir) - .extern_(crate_name, lib_dir.join(format!("lib{crate_name}.rmeta"))) + .extern_(crate_name, format!("lib{crate_name}.rmeta")) .arg("-Zunstable-options") .arg("--scrape-examples-output-path") .arg(&out_example) diff --git a/tests/run-make/rustdoc-shared-flags/rmake.rs b/tests/run-make/rustdoc-shared-flags/rmake.rs index 2db613f7817..d9a16d78a34 100644 --- a/tests/run-make/rustdoc-shared-flags/rmake.rs +++ b/tests/run-make/rustdoc-shared-flags/rmake.rs @@ -1,8 +1,8 @@ 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(); + let rustc_output = rustc().args(args).run().stdout_utf8(); + let rustdoc_output = rustdoc().args(args).run().stdout_utf8(); Diff::new().expected_text("rustc", rustc_output).actual_text("rustdoc", rustdoc_output).run(); } diff --git a/tests/run-make/rustdoc-target-spec-json-path/rmake.rs b/tests/run-make/rustdoc-target-spec-json-path/rmake.rs index 66530a4f08e..3246fc56506 100644 --- a/tests/run-make/rustdoc-target-spec-json-path/rmake.rs +++ b/tests/run-make/rustdoc-target-spec-json-path/rmake.rs @@ -1,14 +1,14 @@ // Test that rustdoc will properly canonicalize the target spec json path just like rustc. -use run_make_support::{rustc, rustdoc, tmp_dir}; +use run_make_support::{cwd, rustc, rustdoc}; fn main() { - let out_dir = tmp_dir().join("rustdoc-target-spec-json-path"); + let out_dir = "rustdoc-target-spec-json-path"; rustc().crate_type("lib").input("dummy_core.rs").target("target.json").run(); rustdoc() .input("my_crate.rs") .output(out_dir) - .library_search_path(tmp_dir()) + .library_search_path(cwd()) .target("target.json") .run(); } diff --git a/tests/run-make/rustdoc-test-args/rmake.rs b/tests/run-make/rustdoc-test-args/rmake.rs index 66f3f7cf131..340ab022880 100644 --- a/tests/run-make/rustdoc-test-args/rmake.rs +++ b/tests/run-make/rustdoc-test-args/rmake.rs @@ -1,4 +1,4 @@ -use run_make_support::{rustdoc, tmp_dir}; +use run_make_support::rustdoc; use std::path::Path; use std::{fs, iter}; @@ -8,8 +8,8 @@ fn generate_a_lot_of_cfgs(path: &Path) { } fn main() { - let arg_file = tmp_dir().join("args"); + let arg_file = Path::new("args"); generate_a_lot_of_cfgs(&arg_file); - rustdoc().out_dir(tmp_dir()).input("foo.rs").arg_file(&arg_file).arg("--test").run(); + rustdoc().input("foo.rs").arg_file(&arg_file).arg("--test").run(); } diff --git a/tests/run-make/rustdoc-themes/rmake.rs b/tests/run-make/rustdoc-themes/rmake.rs index e9da4e25940..c28821b7628 100644 --- a/tests/run-make/rustdoc-themes/rmake.rs +++ b/tests/run-make/rustdoc-themes/rmake.rs @@ -1,13 +1,14 @@ // Test that rustdoc will properly load in a theme file and display it in the theme selector. -use run_make_support::{htmldocck, rustdoc, source_path, tmp_dir}; +use run_make_support::{htmldocck, rustdoc, source_root}; +use std::path::Path; fn main() { - let out_dir = tmp_dir().join("rustdoc-themes"); - let test_css = out_dir.join("test.css"); + let out_dir = Path::new("rustdoc-themes"); + let test_css = "test.css"; let no_script = - std::fs::read_to_string(source_path().join("src/librustdoc/html/static/css/noscript.css")) + std::fs::read_to_string(source_root().join("src/librustdoc/html/static/css/noscript.css")) .unwrap(); let mut test_content = String::new(); diff --git a/tests/run-make/rustdoc-verify-output-files/rmake.rs b/tests/run-make/rustdoc-verify-output-files/rmake.rs index 212e7eaba2d..d2d12ae83a2 100644 --- a/tests/run-make/rustdoc-verify-output-files/rmake.rs +++ b/tests/run-make/rustdoc-verify-output-files/rmake.rs @@ -1,7 +1,7 @@ use std::fs::copy; use std::path::{Path, PathBuf}; -use run_make_support::{copy_dir_all, recursive_diff, rustdoc, tmp_dir}; +use run_make_support::{copy_dir_all, recursive_diff, rustdoc}; #[derive(PartialEq)] enum JsonOutput { @@ -19,8 +19,8 @@ fn generate_docs(out_dir: &Path, json_output: JsonOutput) { } fn main() { - let out_dir = tmp_dir().join("rustdoc"); - let tmp_out_dir = tmp_dir().join("tmp-rustdoc"); + let out_dir = PathBuf::from("rustdoc"); + let tmp_out_dir = PathBuf::from("tmp-rustdoc"); // Generate HTML docs. generate_docs(&out_dir, JsonOutput::No); diff --git a/tests/run-make/rustdoc-with-out-dir-option/rmake.rs b/tests/run-make/rustdoc-with-out-dir-option/rmake.rs index 86471093834..405da8412ae 100644 --- a/tests/run-make/rustdoc-with-out-dir-option/rmake.rs +++ b/tests/run-make/rustdoc-with-out-dir-option/rmake.rs @@ -1,7 +1,7 @@ -use run_make_support::{htmldocck, rustdoc, tmp_dir}; +use run_make_support::{htmldocck, rustdoc}; fn main() { - let out_dir = tmp_dir().join("rustdoc"); + let out_dir = "rustdoc"; rustdoc().input("src/lib.rs").crate_name("foobar").crate_type("lib").output(&out_dir).run(); assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success()); } diff --git a/tests/run-make/rustdoc-with-output-option/rmake.rs b/tests/run-make/rustdoc-with-output-option/rmake.rs index 1a009419273..a3b1c8ca0dd 100644 --- a/tests/run-make/rustdoc-with-output-option/rmake.rs +++ b/tests/run-make/rustdoc-with-output-option/rmake.rs @@ -1,7 +1,7 @@ -use run_make_support::{htmldocck, rustdoc, tmp_dir}; +use run_make_support::{htmldocck, rustdoc}; fn main() { - let out_dir = tmp_dir().join("rustdoc"); + let out_dir = "rustdoc"; rustdoc() .input("src/lib.rs") diff --git a/tests/run-make/rustdoc-with-short-out-dir-option/rmake.rs b/tests/run-make/rustdoc-with-short-out-dir-option/rmake.rs index 6206173ecf1..b536fbe2303 100644 --- a/tests/run-make/rustdoc-with-short-out-dir-option/rmake.rs +++ b/tests/run-make/rustdoc-with-short-out-dir-option/rmake.rs @@ -1,7 +1,7 @@ -use run_make_support::{htmldocck, rustdoc, tmp_dir}; +use run_make_support::{htmldocck, rustdoc}; fn main() { - let out_dir = tmp_dir().join("rustdoc"); + let out_dir = "rustdoc"; rustdoc() .input("src/lib.rs") diff --git a/tests/run-make/same-lib-two-locations-no-panic/bar.rs b/tests/run-make/same-lib-two-locations-no-panic/bar.rs deleted file mode 100644 index bb7b36c496e..00000000000 --- a/tests/run-make/same-lib-two-locations-no-panic/bar.rs +++ /dev/null @@ -1,3 +0,0 @@ -extern crate foo; - -fn main() {} diff --git a/tests/run-make/same-lib-two-locations-no-panic/foo.rs b/tests/run-make/same-lib-two-locations-no-panic/foo.rs deleted file mode 100644 index 82b2dfe9fdb..00000000000 --- a/tests/run-make/same-lib-two-locations-no-panic/foo.rs +++ /dev/null @@ -1 +0,0 @@ -#![crate_name = "foo"] diff --git a/tests/run-make/same-lib-two-locations-no-panic/rmake.rs b/tests/run-make/same-lib-two-locations-no-panic/rmake.rs deleted file mode 100644 index 2900c3c8b74..00000000000 --- a/tests/run-make/same-lib-two-locations-no-panic/rmake.rs +++ /dev/null @@ -1,28 +0,0 @@ -// A path which contains the same rlib or dylib in two locations -// should not cause an assertion panic in the compiler. -// This test tries to replicate the linked issue and checks -// if the bugged error makes a resurgence. - -// See https://github.com/rust-lang/rust/issues/11908 - -//@ ignore-cross-compile - -use run_make_support::{dynamic_lib, rust_lib, rustc, tmp_dir}; -use std::fs; - -fn main() { - let tmp_dir_other = tmp_dir().join("other"); - - fs::create_dir(&tmp_dir_other); - rustc().input("foo.rs").crate_type("dylib").arg("-Cprefer-dynamic").run(); - fs::rename(dynamic_lib("foo"), &tmp_dir_other); - rustc().input("foo.rs").crate_type("dylib").arg("-Cprefer-dynamic").run(); - rustc().input("bar.rs").library_search_path(&tmp_dir_other).run(); - fs::remove_dir_all(tmp_dir()); - - fs::create_dir_all(&tmp_dir_other); - rustc().input("foo.rs").crate_type("rlib").run(); - fs::rename(rust_lib("foo"), &tmp_dir_other); - rustc().input("foo.rs").crate_type("rlib").run(); - rustc().input("bar.rs").library_search_path(tmp_dir_other).run(); -} diff --git a/tests/run-make/stdin-rustc/rmake.rs b/tests/run-make/stdin-rustc/rmake.rs index c07a6df4d84..d599f813563 100644 --- a/tests/run-make/stdin-rustc/rmake.rs +++ b/tests/run-make/stdin-rustc/rmake.rs @@ -1,6 +1,7 @@ //! This test checks rustc `-` (stdin) support -use run_make_support::{is_windows, rustc, tmp_dir}; +use run_make_support::{is_windows, rustc}; +use std::path::PathBuf; const HELLO_WORLD: &str = r#" fn main() { @@ -11,16 +12,16 @@ fn main() { const NOT_UTF8: &[u8] = &[0xff, 0xff, 0xff]; fn main() { - let out_dir = tmp_dir(); - // echo $HELLO_WORLD | rustc - rustc().arg("-").stdin(HELLO_WORLD).run(); assert!( - out_dir.join(if !is_windows() { "rust_out" } else { "rust_out.exe" }).try_exists().unwrap() + PathBuf::from(if !is_windows() { "rust_out" } else { "rust_out.exe" }) + .try_exists() + .unwrap() ); // echo $NOT_UTF8 | rustc - - let output = rustc().arg("-").stdin(NOT_UTF8).run_fail(); - let stderr = String::from_utf8(output.stderr).unwrap(); - assert!(stderr.contains("error: couldn't read from stdin, as it did not contain valid UTF-8")); + rustc().arg("-").stdin(NOT_UTF8).run_fail().assert_stderr_contains( + "error: couldn't read from stdin, as it did not contain valid UTF-8", + ); } diff --git a/tests/run-make/stdin-rustdoc/rmake.rs b/tests/run-make/stdin-rustdoc/rmake.rs index 584a610ed63..a72fe1bc7da 100644 --- a/tests/run-make/stdin-rustdoc/rmake.rs +++ b/tests/run-make/stdin-rustdoc/rmake.rs @@ -1,6 +1,7 @@ //! This test checks rustdoc `-` (stdin) handling -use run_make_support::{rustdoc, tmp_dir}; +use run_make_support::rustdoc; +use std::path::PathBuf; static INPUT: &str = r#" //! ``` @@ -10,8 +11,7 @@ pub struct F; "#; fn main() { - let tmp_dir = tmp_dir(); - let out_dir = tmp_dir.join("doc"); + let out_dir = PathBuf::from("doc"); // rustdoc - rustdoc().arg("-").out_dir(&out_dir).stdin(INPUT).run(); diff --git a/tests/run-make/suspicious-library/Makefile b/tests/run-make/suspicious-library/Makefile deleted file mode 100644 index 3b5ab3c53a5..00000000000 --- a/tests/run-make/suspicious-library/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) foo.rs -C prefer-dynamic - touch $(call DYLIB,foo-something-special) - touch $(call DYLIB,foo-something-special2) - $(RUSTC) bar.rs diff --git a/tests/run-make/suspicious-library/rmake.rs b/tests/run-make/suspicious-library/rmake.rs new file mode 100644 index 00000000000..e789607482b --- /dev/null +++ b/tests/run-make/suspicious-library/rmake.rs @@ -0,0 +1,14 @@ +// This test creates some fake dynamic libraries with nothing inside, +// and checks if rustc avoids them and successfully compiles as a result. + +//@ ignore-cross-compile + +use run_make_support::{dynamic_lib_name, rustc}; +use std::fs::File; + +fn main() { + rustc().input("foo.rs").arg("-Cprefer-dynamic").run(); + File::create(dynamic_lib_name("foo-something-special")).unwrap(); + File::create(dynamic_lib_name("foo-something-special2")).unwrap(); + rustc().input("bar.rs").run(); +} diff --git a/tests/run-make/wasm-abi/rmake.rs b/tests/run-make/wasm-abi/rmake.rs index a2dcafbbe0f..0fc326babd9 100644 --- a/tests/run-make/wasm-abi/rmake.rs +++ b/tests/run-make/wasm-abi/rmake.rs @@ -1,14 +1,14 @@ //@ only-wasm32-wasip1 //@ needs-wasmtime -use run_make_support::{rustc, tmp_dir}; +use run_make_support::rustc; use std::path::Path; use std::process::Command; fn main() { rustc().input("foo.rs").target("wasm32-wasip1").run(); - let file = tmp_dir().join("foo.wasm"); + let file = Path::new("foo.wasm"); run(&file, "return_two_i32", "1\n2\n"); run(&file, "return_two_i64", "3\n4\n"); diff --git a/tests/run-make/wasm-custom-section/rmake.rs b/tests/run-make/wasm-custom-section/rmake.rs index 0303ca05ca6..65f6d0bf347 100644 --- a/tests/run-make/wasm-custom-section/rmake.rs +++ b/tests/run-make/wasm-custom-section/rmake.rs @@ -1,13 +1,13 @@ //@ only-wasm32-wasip1 -use run_make_support::{rustc, tmp_dir, wasmparser}; +use run_make_support::{rustc, wasmparser}; use std::collections::HashMap; fn main() { rustc().input("foo.rs").target("wasm32-wasip1").run(); rustc().input("bar.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); - let file = std::fs::read(&tmp_dir().join("bar.wasm")).unwrap(); + let file = std::fs::read("bar.wasm").unwrap(); let mut custom = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-custom-sections-opt/rmake.rs b/tests/run-make/wasm-custom-sections-opt/rmake.rs index 50916b1bf81..8e66caa6d68 100644 --- a/tests/run-make/wasm-custom-sections-opt/rmake.rs +++ b/tests/run-make/wasm-custom-sections-opt/rmake.rs @@ -1,13 +1,13 @@ //@ only-wasm32-wasip1 -use run_make_support::{rustc, tmp_dir, wasmparser}; +use run_make_support::{rustc, wasmparser}; use std::collections::HashMap; use std::path::Path; fn main() { rustc().input("foo.rs").target("wasm32-wasip1").opt().run(); - verify(&tmp_dir().join("foo.wasm")); + verify(&Path::new("foo.wasm")); } fn verify(path: &Path) { diff --git a/tests/run-make/wasm-export-all-symbols/rmake.rs b/tests/run-make/wasm-export-all-symbols/rmake.rs index f4c51bc4ab4..a6fec1fb0eb 100644 --- a/tests/run-make/wasm-export-all-symbols/rmake.rs +++ b/tests/run-make/wasm-export-all-symbols/rmake.rs @@ -1,6 +1,6 @@ //@ only-wasm32-wasip1 -use run_make_support::{rustc, tmp_dir, wasmparser}; +use run_make_support::{rustc, wasmparser}; use std::collections::HashMap; use std::path::Path; use wasmparser::ExternalKind::*; @@ -18,12 +18,9 @@ fn test(args: &[&str]) { rustc().input("foo.rs").target("wasm32-wasip1").args(args).run(); rustc().input("main.rs").target("wasm32-wasip1").args(args).run(); + verify_exports(Path::new("foo.wasm"), &[("foo", Func), ("FOO", Global), ("memory", Memory)]); verify_exports( - &tmp_dir().join("foo.wasm"), - &[("foo", Func), ("FOO", Global), ("memory", Memory)], - ); - verify_exports( - &tmp_dir().join("main.wasm"), + Path::new("main.wasm"), &[ ("foo", Func), ("FOO", Global), diff --git a/tests/run-make/wasm-import-module/rmake.rs b/tests/run-make/wasm-import-module/rmake.rs index 6eed229e907..0d3152ae99c 100644 --- a/tests/run-make/wasm-import-module/rmake.rs +++ b/tests/run-make/wasm-import-module/rmake.rs @@ -1,6 +1,6 @@ //@ only-wasm32-wasip1 -use run_make_support::{rustc, tmp_dir, wasmparser}; +use run_make_support::{rustc, wasmparser}; use std::collections::HashMap; use wasmparser::TypeRef::Func; @@ -8,7 +8,7 @@ fn main() { rustc().input("foo.rs").target("wasm32-wasip1").run(); rustc().input("bar.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); - let file = std::fs::read(&tmp_dir().join("bar.wasm")).unwrap(); + let file = std::fs::read("bar.wasm").unwrap(); let mut imports = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-override-linker/Makefile b/tests/run-make/wasm-override-linker/Makefile index 52339f9261c..1a01a574dee 100644 --- a/tests/run-make/wasm-override-linker/Makefile +++ b/tests/run-make/wasm-override-linker/Makefile @@ -1,4 +1,7 @@ -# needs-matching-clang +# needs-force-clang-based-tests + +# FIXME(#126180): This test doesn't actually run anywhere, because the only +# CI job that sets RUSTBUILD_FORCE_CLANG_BASED_TESTS runs very few tests. include ../tools.mk diff --git a/tests/run-make/wasm-panic-small/rmake.rs b/tests/run-make/wasm-panic-small/rmake.rs index 373b966401c..304e5d04833 100644 --- a/tests/run-make/wasm-panic-small/rmake.rs +++ b/tests/run-make/wasm-panic-small/rmake.rs @@ -1,7 +1,7 @@ //@ only-wasm32-wasip1 #![deny(warnings)] -use run_make_support::{rustc, tmp_dir}; +use run_make_support::rustc; fn main() { test("a"); @@ -15,7 +15,7 @@ fn test(cfg: &str) { rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().cfg(cfg).run(); - let bytes = std::fs::read(&tmp_dir().join("foo.wasm")).unwrap(); + let bytes = std::fs::read("foo.wasm").unwrap(); println!("{}", bytes.len()); assert!(bytes.len() < 40_000); } diff --git a/tests/run-make/wasm-spurious-import/rmake.rs b/tests/run-make/wasm-spurious-import/rmake.rs index 458c7bfccb7..eb28fdb2b01 100644 --- a/tests/run-make/wasm-spurious-import/rmake.rs +++ b/tests/run-make/wasm-spurious-import/rmake.rs @@ -1,6 +1,6 @@ //@ only-wasm32-wasip1 -use run_make_support::{rustc, tmp_dir, wasmparser}; +use run_make_support::{rustc, wasmparser}; use std::collections::HashMap; fn main() { @@ -13,7 +13,7 @@ fn main() { .arg("-Copt-level=z") .run(); - let file = std::fs::read(&tmp_dir().join("main.wasm")).unwrap(); + let file = std::fs::read("main.wasm").unwrap(); let mut imports = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-stringify-ints-small/rmake.rs b/tests/run-make/wasm-stringify-ints-small/rmake.rs index 9fac0c0c215..8c51e26cc33 100644 --- a/tests/run-make/wasm-stringify-ints-small/rmake.rs +++ b/tests/run-make/wasm-stringify-ints-small/rmake.rs @@ -1,12 +1,12 @@ //@ only-wasm32-wasip1 #![deny(warnings)] -use run_make_support::{rustc, tmp_dir}; +use run_make_support::rustc; fn main() { rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); - let bytes = std::fs::read(&tmp_dir().join("foo.wasm")).unwrap(); + let bytes = std::fs::read("foo.wasm").unwrap(); println!("{}", bytes.len()); assert!(bytes.len() < 50_000); } diff --git a/tests/run-make/wasm-symbols-different-module/rmake.rs b/tests/run-make/wasm-symbols-different-module/rmake.rs index 521d2c31ee6..83970ef0b24 100644 --- a/tests/run-make/wasm-symbols-different-module/rmake.rs +++ b/tests/run-make/wasm-symbols-different-module/rmake.rs @@ -1,7 +1,8 @@ //@ only-wasm32-wasip1 -use run_make_support::{rustc, tmp_dir, wasmparser}; +use run_make_support::{rustc, wasmparser}; use std::collections::{HashMap, HashSet}; +use std::path::Path; fn main() { test_file("foo.rs", &[("a", &["foo"]), ("b", &["foo"])]); @@ -22,7 +23,7 @@ fn test(file: &str, args: &[&str], expected_imports: &[(&str, &[&str])]) { rustc().input(file).target("wasm32-wasip1").args(args).run(); - let file = std::fs::read(&tmp_dir().join(file).with_extension("wasm")).unwrap(); + let file = std::fs::read(Path::new(file).with_extension("wasm")).unwrap(); let mut imports = HashMap::new(); for payload in wasmparser::Parser::new(0).parse_all(&file) { diff --git a/tests/run-make/wasm-symbols-not-exported/rmake.rs b/tests/run-make/wasm-symbols-not-exported/rmake.rs index 1b020b67a38..54604f51a9e 100644 --- a/tests/run-make/wasm-symbols-not-exported/rmake.rs +++ b/tests/run-make/wasm-symbols-not-exported/rmake.rs @@ -1,18 +1,18 @@ //@ only-wasm32-wasip1 -use run_make_support::{rustc, tmp_dir, wasmparser}; +use run_make_support::{rustc, wasmparser}; use std::path::Path; fn main() { rustc().input("foo.rs").target("wasm32-wasip1").run(); - verify_symbols(&tmp_dir().join("foo.wasm")); + verify_symbols(Path::new("foo.wasm")); rustc().input("foo.rs").target("wasm32-wasip1").opt().run(); - verify_symbols(&tmp_dir().join("foo.wasm")); + verify_symbols(Path::new("foo.wasm")); rustc().input("bar.rs").target("wasm32-wasip1").run(); - verify_symbols(&tmp_dir().join("bar.wasm")); + verify_symbols(Path::new("bar.wasm")); rustc().input("bar.rs").target("wasm32-wasip1").opt().run(); - verify_symbols(&tmp_dir().join("bar.wasm")); + verify_symbols(Path::new("bar.wasm")); } fn verify_symbols(path: &Path) { diff --git a/tests/run-make/wasm-symbols-not-imported/rmake.rs b/tests/run-make/wasm-symbols-not-imported/rmake.rs index a653ab61b2c..30408f078bc 100644 --- a/tests/run-make/wasm-symbols-not-imported/rmake.rs +++ b/tests/run-make/wasm-symbols-not-imported/rmake.rs @@ -1,17 +1,17 @@ //@ only-wasm32-wasip1 -use run_make_support::{rustc, tmp_dir, wasmparser}; +use run_make_support::{rustc, wasmparser}; use std::path::Path; fn main() { rustc().input("foo.rs").target("wasm32-wasip1").run(); - verify_symbols(&tmp_dir().join("foo.wasm")); + verify_symbols(Path::new("foo.wasm")); rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").run(); - verify_symbols(&tmp_dir().join("foo.wasm")); + verify_symbols(Path::new("foo.wasm")); rustc().input("foo.rs").target("wasm32-wasip1").opt().run(); - verify_symbols(&tmp_dir().join("foo.wasm")); + verify_symbols(Path::new("foo.wasm")); rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); - verify_symbols(&tmp_dir().join("foo.wasm")); + verify_symbols(Path::new("foo.wasm")); } fn verify_symbols(path: &Path) { diff --git a/tests/run-make/windows-binary-no-external-deps/rmake.rs b/tests/run-make/windows-binary-no-external-deps/rmake.rs index 6704fe04148..61fdb202221 100644 --- a/tests/run-make/windows-binary-no-external-deps/rmake.rs +++ b/tests/run-make/windows-binary-no-external-deps/rmake.rs @@ -2,18 +2,17 @@ //! a "hello world" application by setting `PATH` to `C:\Windows\System32`. //@ only-windows -use run_make_support::{rustc, tmp_dir}; -use std::env; +use run_make_support::{cwd, env_var, rustc}; use std::path::PathBuf; use std::process::Command; fn main() { rustc().input("hello.rs").run(); - let windows_dir = env::var("SystemRoot").unwrap(); + let windows_dir = env_var("SystemRoot"); let system32: PathBuf = [&windows_dir, "System32"].iter().collect(); // Note: This does not use the support wrappers so that we can precisely control the PATH - let exe = tmp_dir().join("hello.exe"); + let exe = cwd().join("hello.exe"); let status = Command::new(exe).env("PATH", &system32).spawn().unwrap().wait().unwrap(); if !status.success() { panic!("Command failed!\noutput status: `{status}`"); diff --git a/tests/run-make/windows-spawn/rmake.rs b/tests/run-make/windows-spawn/rmake.rs index fb9cf1e2149..a6a7acd7ccb 100644 --- a/tests/run-make/windows-spawn/rmake.rs +++ b/tests/run-make/windows-spawn/rmake.rs @@ -1,6 +1,6 @@ //@ only-windows -use run_make_support::{run, rustc, tmp_dir}; +use run_make_support::{run, rustc}; // On Windows `Command` uses `CreateProcessW` to run a new process. // However, in the past std used to not pass in the application name, leaving @@ -10,8 +10,7 @@ use run_make_support::{run, rustc, tmp_dir}; // `foo bar.exe` if foo.exe does not exist. Which is clearly not desired. fn main() { - let out_dir = tmp_dir(); - rustc().input("hello.rs").output(out_dir.join("hopefullydoesntexist bar.exe")).run(); + rustc().input("hello.rs").output("hopefullydoesntexist bar.exe").run(); rustc().input("spawn.rs").run(); run("spawn"); } diff --git a/tests/run-make/windows-ws2_32/rmake.rs b/tests/run-make/windows-ws2_32/rmake.rs index 543f8594478..b3c70c354b4 100644 --- a/tests/run-make/windows-ws2_32/rmake.rs +++ b/tests/run-make/windows-ws2_32/rmake.rs @@ -3,7 +3,7 @@ // Tests that WS2_32.dll is not unnecessarily linked, see issue #85441 use run_make_support::object::{self, read::Object}; -use run_make_support::{rustc, tmp_dir}; +use run_make_support::rustc; use std::fs; fn main() { @@ -15,8 +15,7 @@ fn main() { } fn links_ws2_32(exe: &str) -> bool { - let path = tmp_dir().join(exe); - let binary_data = fs::read(path).unwrap(); + let binary_data = fs::read(exe).unwrap(); let file = object::File::parse(&*binary_data).unwrap(); for import in file.imports().unwrap() { if import.library().eq_ignore_ascii_case(b"WS2_32.dll") { diff --git a/tests/run-pass-valgrind/cast-enum-with-dtor.rs b/tests/run-pass-valgrind/cast-enum-with-dtor.rs index f7ef92df8fb..a57dc373478 100644 --- a/tests/run-pass-valgrind/cast-enum-with-dtor.rs +++ b/tests/run-pass-valgrind/cast-enum-with-dtor.rs @@ -2,14 +2,14 @@ // check dtor calling order when casting enums. +use std::mem; use std::sync::atomic; use std::sync::atomic::Ordering; -use std::mem; enum E { A = 0, B = 1, - C = 2 + C = 2, } static FLAG: atomic::AtomicUsize = atomic::AtomicUsize::new(0); @@ -19,7 +19,7 @@ impl Drop for E { // avoid dtor loop unsafe { mem::forget(mem::replace(self, E::B)) }; - FLAG.store(FLAG.load(Ordering::SeqCst)+1, Ordering::SeqCst); + FLAG.store(FLAG.load(Ordering::SeqCst) + 1, Ordering::SeqCst); } } diff --git a/tests/run-pass-valgrind/cleanup-auto-borrow-obj.rs b/tests/run-pass-valgrind/cleanup-auto-borrow-obj.rs index dfc094abeb9..e4ce80b3305 100644 --- a/tests/run-pass-valgrind/cleanup-auto-borrow-obj.rs +++ b/tests/run-pass-valgrind/cleanup-auto-borrow-obj.rs @@ -7,12 +7,15 @@ static mut DROP_RAN: bool = false; struct Foo; impl Drop for Foo { fn drop(&mut self) { - unsafe { DROP_RAN = true; } + unsafe { + DROP_RAN = true; + } } } - -trait Trait { fn dummy(&self) { } } +trait Trait { + fn dummy(&self) {} +} impl Trait for Foo {} pub fn main() { diff --git a/tests/run-pass-valgrind/coerce-match-calls.rs b/tests/run-pass-valgrind/coerce-match-calls.rs index f6c7151ff10..8c7375610dd 100644 --- a/tests/run-pass-valgrind/coerce-match-calls.rs +++ b/tests/run-pass-valgrind/coerce-match-calls.rs @@ -7,9 +7,15 @@ use std::boxed::Box; pub fn main() { let _: Box<[isize]> = if true { Box::new([1, 2, 3]) } else { Box::new([1]) }; - let _: Box<[isize]> = match true { true => Box::new([1, 2, 3]), false => Box::new([1]) }; + let _: Box<[isize]> = match true { + true => Box::new([1, 2, 3]), + false => Box::new([1]), + }; // Check we don't get over-keen at propagating coercions in the case of casts. let x = if true { 42 } else { 42u8 } as u16; - let x = match true { true => 42, false => 42u8 } as u16; + let x = match true { + true => 42, + false => 42u8, + } as u16; } diff --git a/tests/run-pass-valgrind/coerce-match.rs b/tests/run-pass-valgrind/coerce-match.rs index 3f33264c5a8..95f16a8cc89 100644 --- a/tests/run-pass-valgrind/coerce-match.rs +++ b/tests/run-pass-valgrind/coerce-match.rs @@ -12,11 +12,20 @@ pub fn main() { }; let _: Box<[isize]> = match true { - true => { let b: Box<_> = Box::new([1, 2, 3]); b } - false => { let b: Box<_> = Box::new([1]); b } + true => { + let b: Box<_> = Box::new([1, 2, 3]); + b + } + false => { + let b: Box<_> = Box::new([1]); + b + } }; // Check we don't get over-keen at propagating coercions in the case of casts. let x = if true { 42 } else { 42u8 } as u16; - let x = match true { true => 42, false => 42u8 } as u16; + let x = match true { + true => 42, + false => 42u8, + } as u16; } diff --git a/tests/run-pass-valgrind/down-with-thread-dtors.rs b/tests/run-pass-valgrind/down-with-thread-dtors.rs index 15aeac98c66..0d3745bba5b 100644 --- a/tests/run-pass-valgrind/down-with-thread-dtors.rs +++ b/tests/run-pass-valgrind/down-with-thread-dtors.rs @@ -27,13 +27,17 @@ impl Drop for Bar { impl Drop for Baz { fn drop(&mut self) { - unsafe { HIT = true; } + unsafe { + HIT = true; + } } } fn main() { std::thread::spawn(|| { FOO.with(|_| {}); - }).join().unwrap(); + }) + .join() + .unwrap(); assert!(unsafe { HIT }); } diff --git a/tests/run-pass-valgrind/dst-dtor-1.rs b/tests/run-pass-valgrind/dst-dtor-1.rs index 5b8433f6145..47065151a03 100644 --- a/tests/run-pass-valgrind/dst-dtor-1.rs +++ b/tests/run-pass-valgrind/dst-dtor-1.rs @@ -3,15 +3,19 @@ static mut DROP_RAN: bool = false; struct Foo; impl Drop for Foo { fn drop(&mut self) { - unsafe { DROP_RAN = true; } + unsafe { + DROP_RAN = true; + } } } -trait Trait { fn dummy(&self) { } } +trait Trait { + fn dummy(&self) {} +} impl Trait for Foo {} struct Fat<T: ?Sized> { - f: T + f: T, } pub fn main() { diff --git a/tests/run-pass-valgrind/dst-dtor-2.rs b/tests/run-pass-valgrind/dst-dtor-2.rs index 991fe00950b..d8abebfb447 100644 --- a/tests/run-pass-valgrind/dst-dtor-2.rs +++ b/tests/run-pass-valgrind/dst-dtor-2.rs @@ -3,12 +3,14 @@ static mut DROP_RAN: isize = 0; struct Foo; impl Drop for Foo { fn drop(&mut self) { - unsafe { DROP_RAN += 1; } + unsafe { + DROP_RAN += 1; + } } } struct Fat<T: ?Sized> { - f: T + f: T, } pub fn main() { diff --git a/tests/run-pass-valgrind/dst-dtor-3.rs b/tests/run-pass-valgrind/dst-dtor-3.rs index f0c2dda5ab0..09adaca21c7 100644 --- a/tests/run-pass-valgrind/dst-dtor-3.rs +++ b/tests/run-pass-valgrind/dst-dtor-3.rs @@ -5,11 +5,15 @@ static mut DROP_RAN: bool = false; struct Foo; impl Drop for Foo { fn drop(&mut self) { - unsafe { DROP_RAN = true; } + unsafe { + DROP_RAN = true; + } } } -trait Trait { fn dummy(&self) { } } +trait Trait { + fn dummy(&self) {} +} impl Trait for Foo {} pub fn main() { diff --git a/tests/run-pass-valgrind/dst-dtor-4.rs b/tests/run-pass-valgrind/dst-dtor-4.rs index ad6d46f7c08..a66ac8e3cfc 100644 --- a/tests/run-pass-valgrind/dst-dtor-4.rs +++ b/tests/run-pass-valgrind/dst-dtor-4.rs @@ -5,7 +5,9 @@ static mut DROP_RAN: isize = 0; struct Foo; impl Drop for Foo { fn drop(&mut self) { - unsafe { DROP_RAN += 1; } + unsafe { + DROP_RAN += 1; + } } } diff --git a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs b/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs index ece4dea9aaf..5d3f558a63a 100644 --- a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs +++ b/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs @@ -43,7 +43,6 @@ impl FnOnce<()> for D { } } - fn main() { let x = *(Box::new(A) as Box<dyn FnOnce<(), Output = String>>); assert_eq!(x.call_once(()), format!("hello")); diff --git a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs b/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs index 94df2b0b83f..9b6648f2e27 100644 --- a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs +++ b/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs @@ -51,7 +51,6 @@ impl FnOnce<(String, Box<str>)> for D { } } - fn main() { let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str()); let x = *(Box::new(A) as Box<dyn FnOnce<(String, Box<str>), Output = String>>); @@ -61,10 +60,10 @@ fn main() { assert_eq!(x.call_once((s1, s2)), format!("42")); let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str()); let x = *(Box::new(C(format!("jumping fox"))) - as Box<dyn FnOnce<(String, Box<str>), Output = String>>); + as Box<dyn FnOnce<(String, Box<str>), Output = String>>); assert_eq!(x.call_once((s1, s2)), format!("jumping fox")); let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str()); let x = *(Box::new(D(Box::new(format!("lazy dog")))) - as Box<dyn FnOnce<(String, Box<str>), Output = String>>); + as Box<dyn FnOnce<(String, Box<str>), Output = String>>); assert_eq!(x.call_once((s1, s2)), format!("lazy dog")); } diff --git a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects.rs b/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects.rs index 3d67101e734..3f6b6d262b5 100644 --- a/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects.rs +++ b/tests/run-pass-valgrind/unsized-locals/by-value-trait-objects.rs @@ -36,7 +36,6 @@ impl Foo for D { } } - fn main() { let x = *(Box::new(A) as Box<dyn Foo>); assert_eq!(x.foo(), format!("hello")); diff --git a/tests/rustdoc-js-std/parser-errors.js b/tests/rustdoc-js-std/parser-errors.js index ffd169812b6..c4d7c2b0b85 100644 --- a/tests/rustdoc-js-std/parser-errors.js +++ b/tests/rustdoc-js-std/parser-errors.js @@ -24,7 +24,7 @@ const PARSED = [ original: "-> *", returned: [], userQuery: "-> *", - error: "Unexpected `*` after ` `", + error: "Unexpected `*` after ` ` (not a valid identifier)", }, { query: 'a<"P">', @@ -204,16 +204,25 @@ const PARSED = [ original: "_:", returned: [], userQuery: "_:", - error: "Unexpected `:` (expected path after type filter `_:`)", + error: "Unexpected `_` (not a valid identifier)", }, { - query: "_:a", + query: "ab:", elems: [], foundElems: 0, - original: "_:a", + original: "ab:", returned: [], - userQuery: "_:a", - error: "Unknown type filter `_`", + userQuery: "ab:", + error: "Unexpected `:` (expected path after type filter `ab:`)", + }, + { + query: "a:b", + elems: [], + foundElems: 0, + original: "a:b", + returned: [], + userQuery: "a:b", + error: "Unknown type filter `a`", }, { query: "a-bb", @@ -240,7 +249,7 @@ const PARSED = [ original: "ab'", returned: [], userQuery: "ab'", - error: "Unexpected `'` after `b`", + error: "Unexpected `'` after `b` (not a valid identifier)", }, { query: "a->", diff --git a/tests/rustdoc-js/assoc-type-backtrack.rs b/tests/rustdoc-js/assoc-type-backtrack.rs index c3cdd78c6e1..2dfede9dc38 100644 --- a/tests/rustdoc-js/assoc-type-backtrack.rs +++ b/tests/rustdoc-js/assoc-type-backtrack.rs @@ -5,22 +5,27 @@ pub trait MyTrait2<X> { pub trait MyTrait { type Item; fn next(&mut self) -> Option<Self::Item>; - fn fold<B, F>(self, init: B, f: F) -> B where + fn fold<B, F>(self, init: B, f: F) -> B + where Self: Sized, - F: MyTrait2<(B, Self::Item), Output=B>; + F: MyTrait2<(B, Self::Item), Output = B>; } pub struct Cloned<I>(I); -impl<'a, T, I> MyTrait for Cloned<I> where +impl<'a, T, I> MyTrait for Cloned<I> +where T: 'a + Clone, - I: MyTrait<Item = &'a T> + I: MyTrait<Item = &'a T>, { type Item = T; - fn next(&mut self) -> Option<Self::Item> { loop {} } - fn fold<B, F>(self, init: B, f: F) -> B where + fn next(&mut self) -> Option<Self::Item> { + loop {} + } + fn fold<B, F>(self, init: B, f: F) -> B + where Self: Sized, - F: MyTrait2<(B, Self::Item), Output=B> + F: MyTrait2<(B, Self::Item), Output = B>, { loop {} } @@ -32,7 +37,7 @@ pub trait MyFuture { pub trait MyIntoFuture { type Output; - type Fut: MyFuture<Output=Self::Output>; + type Fut: MyFuture<Output = Self::Output>; fn into_future(self) -> Self::Fut; fn into_future_2(self, other: Self) -> Self::Fut; } diff --git a/tests/rustdoc-js/assoc-type-loop.rs b/tests/rustdoc-js/assoc-type-loop.rs index f123c83f50f..09efe8c7be5 100644 --- a/tests/rustdoc-js/assoc-type-loop.rs +++ b/tests/rustdoc-js/assoc-type-loop.rs @@ -1,9 +1,9 @@ -#![crate_name="foo"] +#![crate_name = "foo"] // reduced from sqlx 0.7.3 use std::future::Future; -use std::pin::Pin; use std::ops::{Deref, DerefMut}; +use std::pin::Pin; pub enum Error {} pub trait Acquire<'c> { type Database: Database; @@ -16,7 +16,7 @@ pub trait Connection { type Database: Database; type Options: ConnectionOptions<Connection = Self>; fn begin( - &mut self + &mut self, ) -> Pin<Box<dyn Future<Output = Result<Transaction<'_, Self::Database>, Error>> + Send + '_>> where Self: Sized; @@ -28,7 +28,8 @@ pub struct Transaction<'c, DB: Database> { _db: &'c DB, } impl<'t, 'c, DB: Database> Acquire<'t> for &'t mut Transaction<'c, DB> - where <DB as Database>::Connection: Send +where + <DB as Database>::Connection: Send, { type Database = DB; type Connection = &'t mut <DB as Database>::Connection; diff --git a/tests/rustdoc-js/auxiliary/interner.rs b/tests/rustdoc-js/auxiliary/interner.rs index c95029be9f0..e4e4ff6276d 100644 --- a/tests/rustdoc-js/auxiliary/interner.rs +++ b/tests/rustdoc-js/auxiliary/interner.rs @@ -77,17 +77,14 @@ pub trait Interner: Sized { type ClosureKind: Copy + Debug + Hash + Eq; // Required method - fn mk_canonical_var_infos( - self, - infos: &[CanonicalVarInfo<Self>] - ) -> Self::CanonicalVars; + fn mk_canonical_var_infos(self, infos: &[CanonicalVarInfo<Self>]) -> Self::CanonicalVars; } pub trait DebugWithInfcx<I: Interner>: Debug { // Required method fn fmt<Infcx: InferCtxtLike<Interner = I>>( this: WithInfcx<'_, Infcx, &Self>, - f: &mut Formatter<'_> + f: &mut Formatter<'_>, ) -> std::fmt::Result; } @@ -130,11 +127,7 @@ pub struct TypeFlags; pub trait Ty<I: Interner<Ty = Self>> { // Required method - fn new_anon_bound( - interner: I, - debruijn: DebruijnIndex, - var: BoundVar - ) -> Self; + fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self; } pub trait PlaceholderLike { @@ -152,12 +145,7 @@ pub struct BoundVar; pub struct ConstKind<I>(std::marker::PhantomData<I>); pub trait Const<I: Interner<Const = Self>> { // Required method - fn new_anon_bound( - interner: I, - debruijn: DebruijnIndex, - var: BoundVar, - ty: I::Ty - ) -> Self; + fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar, ty: I::Ty) -> Self; } pub trait ConstTy<I: Interner> { @@ -170,25 +158,28 @@ pub struct DebruijnIndex; pub struct RegionKind<I>(std::marker::PhantomData<I>); pub trait Region<I: Interner<Region = Self>> { // Required method - fn new_anon_bound( - interner: I, - debruijn: DebruijnIndex, - var: BoundVar - ) -> Self; + fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self; } pub trait TypeVisitor<I: Interner>: Sized { type Result: VisitorResult = (); // Provided methods - fn visit_binder<T: TypeVisitable<I>>( - &mut self, - t: &I::Binder<T> - ) -> Self::Result { unimplemented!() } - fn visit_ty(&mut self, t: I::Ty) -> Self::Result { unimplemented!() } - fn visit_region(&mut self, _r: I::Region) -> Self::Result { unimplemented!() } - fn visit_const(&mut self, c: I::Const) -> Self::Result { unimplemented!() } - fn visit_predicate(&mut self, p: I::Predicate) -> Self::Result { unimplemented!() } + fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &I::Binder<T>) -> Self::Result { + unimplemented!() + } + fn visit_ty(&mut self, t: I::Ty) -> Self::Result { + unimplemented!() + } + fn visit_region(&mut self, _r: I::Region) -> Self::Result { + unimplemented!() + } + fn visit_const(&mut self, c: I::Const) -> Self::Result { + unimplemented!() + } + fn visit_predicate(&mut self, p: I::Predicate) -> Self::Result { + unimplemented!() + } } pub trait VisitorResult { @@ -206,7 +197,9 @@ impl VisitorResult for () { fn output() -> Self {} fn from_residual(_: Self::Residual) -> Self {} fn from_branch(_: ControlFlow<Self::Residual>) -> Self {} - fn branch(self) -> ControlFlow<Self::Residual> { ControlFlow::Continue(()) } + fn branch(self) -> ControlFlow<Self::Residual> { + ControlFlow::Continue(()) + } } pub struct WithInfcx<'a, Infcx: InferCtxtLike, T> { @@ -221,24 +214,18 @@ pub trait InferCtxtLike { fn interner(&self) -> Self::Interner; fn universe_of_ty(&self, ty: TyVid) -> Option<UniverseIndex>; fn root_ty_var(&self, vid: TyVid) -> TyVid; - fn probe_ty_var( - &self, - vid: TyVid - ) -> Option<<Self::Interner as Interner>::Ty>; + fn probe_ty_var(&self, vid: TyVid) -> Option<<Self::Interner as Interner>::Ty>; fn universe_of_lt( &self, - lt: <Self::Interner as Interner>::InferRegion + lt: <Self::Interner as Interner>::InferRegion, ) -> Option<UniverseIndex>; fn opportunistic_resolve_lt_var( &self, - vid: <Self::Interner as Interner>::InferRegion + vid: <Self::Interner as Interner>::InferRegion, ) -> Option<<Self::Interner as Interner>::Region>; fn universe_of_ct(&self, ct: ConstVid) -> Option<UniverseIndex>; fn root_ct_var(&self, vid: ConstVid) -> ConstVid; - fn probe_ct_var( - &self, - vid: ConstVid - ) -> Option<<Self::Interner as Interner>::Const>; + fn probe_ct_var(&self, vid: ConstVid) -> Option<<Self::Interner as Interner>::Const>; } pub struct TyVid; diff --git a/tests/rustdoc-js/basic.js b/tests/rustdoc-js/basic.js index e186d510887..c38b8435c2d 100644 --- a/tests/rustdoc-js/basic.js +++ b/tests/rustdoc-js/basic.js @@ -1,6 +1,6 @@ const EXPECTED = { 'query': 'Fo', 'others': [ - { 'path': 'basic', 'name': 'Foo' }, + { 'path': 'basic', 'name': 'Foo', 'desc': 'Docs for Foo' }, ], }; diff --git a/tests/rustdoc-js/doc-alias.js b/tests/rustdoc-js/doc-alias.js index 7e4e8a776d8..e57bd71419d 100644 --- a/tests/rustdoc-js/doc-alias.js +++ b/tests/rustdoc-js/doc-alias.js @@ -5,6 +5,7 @@ const EXPECTED = [ { 'path': 'doc_alias', 'name': 'Struct', + 'desc': 'Doc for <code>Struct</code>', 'alias': 'StructItem', 'href': '../doc_alias/struct.Struct.html', 'is_alias': true @@ -17,6 +18,7 @@ const EXPECTED = [ { 'path': 'doc_alias::Struct', 'name': 'field', + 'desc': 'Doc for <code>Struct</code>’s <code>field</code>', 'alias': 'StructFieldItem', 'href': '../doc_alias/struct.Struct.html#structfield.field', 'is_alias': true @@ -29,6 +31,7 @@ const EXPECTED = [ { 'path': 'doc_alias::Struct', 'name': 'method', + 'desc': 'Doc for <code>Struct::method</code>', 'alias': 'StructMethodItem', 'href': '../doc_alias/struct.Struct.html#method.method', 'is_alias': true @@ -45,6 +48,7 @@ const EXPECTED = [ { 'path': 'doc_alias::Struct', 'name': 'ImplConstItem', + 'desc': 'Doc for <code>Struct::ImplConstItem</code>', 'alias': 'StructImplConstItem', 'href': '../doc_alias/struct.Struct.html#associatedconstant.ImplConstItem', 'is_alias': true @@ -57,6 +61,7 @@ const EXPECTED = [ { 'path': 'doc_alias::Struct', 'name': 'function', + 'desc': 'Doc for <code>Trait::function</code> implemented for Struct', 'alias': 'ImplTraitFunction', 'href': '../doc_alias/struct.Struct.html#method.function', 'is_alias': true @@ -69,6 +74,7 @@ const EXPECTED = [ { 'path': 'doc_alias', 'name': 'Enum', + 'desc': 'Doc for <code>Enum</code>', 'alias': 'EnumItem', 'href': '../doc_alias/enum.Enum.html', 'is_alias': true @@ -81,6 +87,7 @@ const EXPECTED = [ { 'path': 'doc_alias::Enum', 'name': 'Variant', + 'desc': 'Doc for <code>Enum::Variant</code>', 'alias': 'VariantItem', 'href': '../doc_alias/enum.Enum.html#variant.Variant', 'is_alias': true @@ -93,6 +100,7 @@ const EXPECTED = [ { 'path': 'doc_alias::Enum', 'name': 'method', + 'desc': 'Doc for <code>Enum::method</code>', 'alias': 'EnumMethodItem', 'href': '../doc_alias/enum.Enum.html#method.method', 'is_alias': true @@ -105,6 +113,7 @@ const EXPECTED = [ { 'path': 'doc_alias', 'name': 'Typedef', + 'desc': 'Doc for type alias <code>Typedef</code>', 'alias': 'TypedefItem', 'href': '../doc_alias/type.Typedef.html', 'is_alias': true @@ -117,6 +126,7 @@ const EXPECTED = [ { 'path': 'doc_alias', 'name': 'Trait', + 'desc': 'Doc for <code>Trait</code>', 'alias': 'TraitItem', 'href': '../doc_alias/trait.Trait.html', 'is_alias': true @@ -129,6 +139,7 @@ const EXPECTED = [ { 'path': 'doc_alias::Trait', 'name': 'Target', + 'desc': 'Doc for <code>Trait::Target</code>', 'alias': 'TraitTypeItem', 'href': '../doc_alias/trait.Trait.html#associatedtype.Target', 'is_alias': true @@ -141,6 +152,7 @@ const EXPECTED = [ { 'path': 'doc_alias::Trait', 'name': 'AssociatedConst', + 'desc': 'Doc for <code>Trait::AssociatedConst</code>', 'alias': 'AssociatedConstItem', 'href': '../doc_alias/trait.Trait.html#associatedconstant.AssociatedConst', 'is_alias': true @@ -153,6 +165,7 @@ const EXPECTED = [ { 'path': 'doc_alias::Trait', 'name': 'function', + 'desc': 'Doc for <code>Trait::function</code>', 'alias': 'TraitFunctionItem', 'href': '../doc_alias/trait.Trait.html#tymethod.function', 'is_alias': true @@ -165,6 +178,7 @@ const EXPECTED = [ { 'path': 'doc_alias', 'name': 'function', + 'desc': 'Doc for <code>function</code>', 'alias': 'FunctionItem', 'href': '../doc_alias/fn.function.html', 'is_alias': true @@ -177,6 +191,7 @@ const EXPECTED = [ { 'path': 'doc_alias', 'name': 'Module', + 'desc': 'Doc for <code>Module</code>', 'alias': 'ModuleItem', 'href': '../doc_alias/Module/index.html', 'is_alias': true @@ -189,6 +204,7 @@ const EXPECTED = [ { 'path': 'doc_alias', 'name': 'Const', + 'desc': 'Doc for <code>Const</code>', 'alias': 'ConstItem', 'href': '../doc_alias/constant.Const.html', 'is_alias': true @@ -205,6 +221,7 @@ const EXPECTED = [ { 'path': 'doc_alias', 'name': 'Static', + 'desc': 'Doc for <code>Static</code>', 'alias': 'StaticItem', 'href': '../doc_alias/static.Static.html', 'is_alias': true @@ -217,6 +234,7 @@ const EXPECTED = [ { 'path': 'doc_alias', 'name': 'Union', + 'desc': 'Doc for <code>Union</code>', 'alias': 'UnionItem', 'href': '../doc_alias/union.Union.html', 'is_alias': true @@ -225,6 +243,7 @@ const EXPECTED = [ { 'path': 'doc_alias::Union', 'name': 'union_item', + 'desc': 'Doc for <code>Union::union_item</code>', 'href': '../doc_alias/union.Union.html#structfield.union_item' }, ], @@ -235,6 +254,7 @@ const EXPECTED = [ { 'path': 'doc_alias::Union', 'name': 'union_item', + 'desc': 'Doc for <code>Union::union_item</code>', 'alias': 'UnionFieldItem', 'href': '../doc_alias/union.Union.html#structfield.union_item', 'is_alias': true @@ -247,6 +267,7 @@ const EXPECTED = [ { 'path': 'doc_alias::Union', 'name': 'method', + 'desc': 'Doc for <code>Union::method</code>', 'alias': 'UnionMethodItem', 'href': '../doc_alias/union.Union.html#method.method', 'is_alias': true @@ -259,6 +280,7 @@ const EXPECTED = [ { 'path': 'doc_alias', 'name': 'Macro', + 'desc': 'Doc for <code>Macro</code>', 'alias': 'MacroItem', 'href': '../doc_alias/macro.Macro.html', 'is_alias': true diff --git a/tests/rustdoc-js/doc-alias.rs b/tests/rustdoc-js/doc-alias.rs index 750b7b757bc..bf075385327 100644 --- a/tests/rustdoc-js/doc-alias.rs +++ b/tests/rustdoc-js/doc-alias.rs @@ -1,12 +1,16 @@ +/// Doc for `Struct` #[doc(alias = "StructItem")] pub struct Struct { + /// Doc for `Struct`'s `field` #[doc(alias = "StructFieldItem")] pub field: u32, } impl Struct { + /// Doc for `Struct::ImplConstItem` #[doc(alias = "StructImplConstItem")] pub const ImplConstItem: i32 = 0; + /// Doc for `Struct::method` #[doc(alias = "StructMethodItem")] pub fn method(&self) {} } @@ -15,61 +19,80 @@ impl Trait for Struct { type Target = u32; const AssociatedConst: i32 = 12; + /// Doc for `Trait::function` implemented for Struct #[doc(alias = "ImplTraitFunction")] - fn function() -> Self::Target { 0 } + fn function() -> Self::Target { + 0 + } } +/// Doc for `Enum` #[doc(alias = "EnumItem")] pub enum Enum { + /// Doc for `Enum::Variant` #[doc(alias = "VariantItem")] Variant, } impl Enum { + /// Doc for `Enum::method` #[doc(alias = "EnumMethodItem")] pub fn method(&self) {} } +/// Doc for type alias `Typedef` #[doc(alias = "TypedefItem")] pub type Typedef = i32; +/// Doc for `Trait` #[doc(alias = "TraitItem")] pub trait Trait { + /// Doc for `Trait::Target` #[doc(alias = "TraitTypeItem")] type Target; + /// Doc for `Trait::AssociatedConst` #[doc(alias = "AssociatedConstItem")] const AssociatedConst: i32; + /// Doc for `Trait::function` #[doc(alias = "TraitFunctionItem")] fn function() -> Self::Target; } +/// Doc for `function` #[doc(alias = "FunctionItem")] pub fn function() {} +/// Doc for `Module` #[doc(alias = "ModuleItem")] pub mod Module {} +/// Doc for `Const` #[doc(alias = "ConstItem")] pub const Const: u32 = 0; +/// Doc for `Static` #[doc(alias = "StaticItem")] pub static Static: u32 = 0; +/// Doc for `Union` #[doc(alias = "UnionItem")] pub union Union { + /// Doc for `Union::union_item` #[doc(alias = "UnionFieldItem")] pub union_item: u32, pub y: f32, } impl Union { + /// Doc for `Union::method` #[doc(alias = "UnionMethodItem")] pub fn method(&self) {} } +/// Doc for `Macro` #[doc(alias = "MacroItem")] #[macro_export] macro_rules! Macro { - () => {} + () => {}; } diff --git a/tests/rustdoc-js/enum-variant-not-type.rs b/tests/rustdoc-js/enum-variant-not-type.rs index 421bddf6289..f0facd63cfc 100644 --- a/tests/rustdoc-js/enum-variant-not-type.rs +++ b/tests/rustdoc-js/enum-variant-not-type.rs @@ -5,10 +5,14 @@ pub trait MyTrait { fn not_appearing(&self) -> Option<&Self::T>; } -pub fn my_fn<X>(t: X) -> X { t } +pub fn my_fn<X>(t: X) -> X { + t +} pub trait AutoCorrectConfounder { type InsertUnnecessarilyLongTypeNameHere; - fn assoc_type_acts_like_generic(&self, x: &Self::InsertUnnecessarilyLongTypeNameHere) - -> Option<&Self::InsertUnnecessarilyLongTypeNameHere>; + fn assoc_type_acts_like_generic( + &self, + x: &Self::InsertUnnecessarilyLongTypeNameHere, + ) -> Option<&Self::InsertUnnecessarilyLongTypeNameHere>; } diff --git a/tests/rustdoc-js/foreign-type-path.rs b/tests/rustdoc-js/foreign-type-path.rs index 83400104ea7..f9228c7b9ac 100644 --- a/tests/rustdoc-js/foreign-type-path.rs +++ b/tests/rustdoc-js/foreign-type-path.rs @@ -2,12 +2,11 @@ pub mod aaaaaaa { - extern { + extern "C" { pub type MyForeignType; } impl MyForeignType { pub fn my_method() {} } - } diff --git a/tests/rustdoc-js/full-path-function.rs b/tests/rustdoc-js/full-path-function.rs index 8dcc3f2b69d..a1a9220654d 100644 --- a/tests/rustdoc-js/full-path-function.rs +++ b/tests/rustdoc-js/full-path-function.rs @@ -2,16 +2,26 @@ pub mod sac { pub struct Sac; impl Sac { - pub fn len(&self) -> usize { 0 } + pub fn len(&self) -> usize { + 0 + } } } pub mod b { pub struct Sac; impl Sac { - pub fn len(&self) -> usize { 0 } - pub fn bar(&self, w: u32) -> usize { 0 } - pub fn bar2(&self, w: u32) -> u32 { 0 } - pub fn string(w: String) -> u32 { 0 } + pub fn len(&self) -> usize { + 0 + } + pub fn bar(&self, w: u32) -> usize { + 0 + } + pub fn bar2(&self, w: u32) -> u32 { + 0 + } + pub fn string(w: String) -> u32 { + 0 + } } } diff --git a/tests/rustdoc-js/gat.rs b/tests/rustdoc-js/gat.rs index b4861cc683f..7a2b5551114 100644 --- a/tests/rustdoc-js/gat.rs +++ b/tests/rustdoc-js/gat.rs @@ -2,7 +2,15 @@ pub trait Foo { type Assoc<T>; } -pub fn sample<X: Foo<Assoc<u8> = u8>>(_: X) -> u32 { loop {} } -pub fn synergy(_: impl Foo<Assoc<u8> = u8>) -> ! { loop {} } -pub fn consider(_: impl Foo<Assoc<u8> = u32>) -> bool { loop {} } -pub fn integrate<T>(_: impl Foo<Assoc<T> = T>) -> T { loop {} } +pub fn sample<X: Foo<Assoc<u8> = u8>>(_: X) -> u32 { + loop {} +} +pub fn synergy(_: impl Foo<Assoc<u8> = u8>) -> ! { + loop {} +} +pub fn consider(_: impl Foo<Assoc<u8> = u32>) -> bool { + loop {} +} +pub fn integrate<T>(_: impl Foo<Assoc<T> = T>) -> T { + loop {} +} diff --git a/tests/rustdoc-js/generics-impl.rs b/tests/rustdoc-js/generics-impl.rs index 696218021d5..27d44fdd7e9 100644 --- a/tests/rustdoc-js/generics-impl.rs +++ b/tests/rustdoc-js/generics-impl.rs @@ -1,4 +1,4 @@ -use std::io::{Result as IoResult, Read}; +use std::io::{Read, Result as IoResult}; pub struct Aaaaaaa; @@ -29,7 +29,10 @@ impl<T: Read> Ddddddd<T> { pub fn ggggggg(self) -> u64 { 1 } - pub fn hhhhhhh() -> Self where T: Default { + pub fn hhhhhhh() -> Self + where + T: Default, + { Ddddddd(T::default()) } } diff --git a/tests/rustdoc-js/generics-trait.rs b/tests/rustdoc-js/generics-trait.rs index 20db117ccd5..58c86361e41 100644 --- a/tests/rustdoc-js/generics-trait.rs +++ b/tests/rustdoc-js/generics-trait.rs @@ -1,8 +1,16 @@ pub trait SomeTrait {} pub trait OtherThingxxxxxxxx {} -pub fn alef<T: OtherThingxxxxxxxx>() -> Result<T, ()> { loop {} } -pub fn bet<T: SomeTrait>() -> Result<T, ()> { loop {} } +pub fn alef<T: OtherThingxxxxxxxx>() -> Result<T, ()> { + loop {} +} +pub fn bet<T: SomeTrait>() -> Result<T, ()> { + loop {} +} -pub fn alpha<T: OtherThingxxxxxxxx>(_param: Result<T, ()>) { loop {} } -pub fn beta<T: SomeTrait>(_param: Result<T, ()>) { loop {} } +pub fn alpha<T: OtherThingxxxxxxxx>(_param: Result<T, ()>) { + loop {} +} +pub fn beta<T: SomeTrait>(_param: Result<T, ()>) { + loop {} +} diff --git a/tests/rustdoc-js/generics.rs b/tests/rustdoc-js/generics.rs index 055c51c7ec5..c3ca1366614 100644 --- a/tests/rustdoc-js/generics.rs +++ b/tests/rustdoc-js/generics.rs @@ -3,26 +3,41 @@ pub struct Q; pub struct R<T>(T); // returns test -pub fn alef() -> R<P> { loop {} } -pub fn bet() -> R<Q> { loop {} } +pub fn alef() -> R<P> { + loop {} +} +pub fn bet() -> R<Q> { + loop {} +} // in_args test -pub fn alpha(_x: R<P>) { loop {} } -pub fn beta(_x: R<Q>) { loop {} } +pub fn alpha(_x: R<P>) { + loop {} +} +pub fn beta(_x: R<Q>) { + loop {} +} // test case with multiple appearances of the same type -pub struct ExtraCreditStructMulti<T, U> { t: T, u: U } +pub struct ExtraCreditStructMulti<T, U> { + t: T, + u: U, +} pub struct ExtraCreditInnerMulti {} pub fn extracreditlabhomework( - _param: ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti> -) { loop {} } -pub fn redherringmatchforextracredit( - _param: ExtraCreditStructMulti<ExtraCreditInnerMulti, ()> -) { loop {} } + _param: ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>, +) { + loop {} +} +pub fn redherringmatchforextracredit(_param: ExtraCreditStructMulti<ExtraCreditInnerMulti, ()>) { + loop {} +} pub trait TraitCat {} pub trait TraitDog {} pub fn gamma<T: TraitCat + TraitDog>(t: T) {} -pub fn super_soup(s: Result<String, i32>) -> Result<String, i32> { s } +pub fn super_soup(s: Result<String, i32>) -> Result<String, i32> { + s +} diff --git a/tests/rustdoc-js/hof.rs b/tests/rustdoc-js/hof.rs index 4d2c6e331ca..e4d550250e8 100644 --- a/tests/rustdoc-js/hof.rs +++ b/tests/rustdoc-js/hof.rs @@ -4,9 +4,9 @@ pub struct First<T>(T); pub struct Second<T>(T); pub struct Third<T>(T); -pub fn fn_ptr(_: fn (First<u32>) -> !, _: bool) {} -pub fn fn_once(_: impl FnOnce (Second<u32>) -> !, _: u8) {} -pub fn fn_mut(_: impl FnMut (Third<u32>) -> !, _: i8) {} -pub fn fn_(_: impl Fn (u32) -> !, _: char) {} +pub fn fn_ptr(_: fn(First<u32>) -> !, _: bool) {} +pub fn fn_once(_: impl FnOnce(Second<u32>) -> !, _: u8) {} +pub fn fn_mut(_: impl FnMut(Third<u32>) -> !, _: i8) {} +pub fn fn_(_: impl Fn(u32) -> !, _: char) {} pub fn multiple(_: impl Fn(&'static str, &'static str) -> i8) {} diff --git a/tests/rustdoc-js/macro-search.rs b/tests/rustdoc-js/macro-search.rs index dc397490cf5..7fa9cbc4ab2 100644 --- a/tests/rustdoc-js/macro-search.rs +++ b/tests/rustdoc-js/macro-search.rs @@ -1,10 +1,10 @@ #[macro_export] macro_rules! abracadabra { - () => {} + () => {}; } #[macro_export] macro_rules! abracadabra_b { - () => {} + () => {}; } pub fn abracadabra() {} pub fn abracadabra_c() {} diff --git a/tests/rustdoc-js/never-search.rs b/tests/rustdoc-js/never-search.rs index 299b4660dae..800f9ead8b3 100644 --- a/tests/rustdoc-js/never-search.rs +++ b/tests/rustdoc-js/never-search.rs @@ -3,11 +3,27 @@ #[allow(nonstandard_style)] pub struct never; -pub fn loops() -> ! { loop {} } -pub fn returns() -> never { never } +pub fn loops() -> ! { + loop {} +} +pub fn returns() -> never { + never +} -pub fn impossible(x: !) { match x {} } -pub fn uninteresting(x: never) { match x { never => {} } } +pub fn impossible(x: !) { + match x {} +} +pub fn uninteresting(x: never) { + match x { + never => {} + } +} -pub fn box_impossible(x: Box<!>) { match *x {} } -pub fn box_uninteresting(x: Box<never>) { match *x { never => {} } } +pub fn box_impossible(x: Box<!>) { + match *x {} +} +pub fn box_uninteresting(x: Box<never>) { + match *x { + never => {} + } +} diff --git a/tests/rustdoc-js/non-english-identifier.js b/tests/rustdoc-js/non-english-identifier.js new file mode 100644 index 00000000000..1765a69152a --- /dev/null +++ b/tests/rustdoc-js/non-english-identifier.js @@ -0,0 +1,163 @@ +const PARSED = [ + { + query: '中文', + elems: [{ + name: "中文", + fullPath: ["中文"], + pathWithoutLast: [], + pathLast: "中文", + generics: [], + typeFilter: -1, + }], + returned: [], + foundElems: 1, + original: "中文", + userQuery: "中文", + error: null, + }, + { + query: '_0Mixed中英文', + elems: [{ + name: "_0mixed中英文", + fullPath: ["_0mixed中英文"], + pathWithoutLast: [], + pathLast: "_0mixed中英文", + generics: [], + typeFilter: -1, + }], + foundElems: 1, + original: "_0Mixed中英文", + returned: [], + userQuery: "_0mixed中英文", + error: null, + }, + { + query: 'my_crate::中文API', + elems: [{ + name: "my_crate::中文api", + fullPath: ["my_crate", "中文api"], + pathWithoutLast: ["my_crate"], + pathLast: "中文api", + generics: [], + typeFilter: -1, + }], + foundElems: 1, + original: "my_crate::中文API", + returned: [], + userQuery: "my_crate::中文api", + error: null, + }, + { + query: '类型A,类型B<约束C>->返回类型<关联类型=路径::约束D>', + elems: [{ + name: "类型a", + fullPath: ["类型a"], + pathWithoutLast: [], + pathLast: "类型a", + generics: [], + }, { + name: "类型b", + fullPath: ["类型b"], + pathWithoutLast: [], + pathLast: "类型b", + generics: [{ + name: "约束c", + fullPath: ["约束c"], + pathWithoutLast: [], + pathLast: "约束c", + generics: [], + }], + }], + foundElems: 3, + totalElems: 5, + literalSearch: true, + original: "类型A,类型B<约束C>->返回类型<关联类型=路径::约束D>", + returned: [{ + name: "返回类型", + fullPath: ["返回类型"], + pathWithoutLast: [], + pathLast: "返回类型", + generics: [], + }], + userQuery: "类型a,类型b<约束c>->返回类型<关联类型=路径::约束d>", + error: null, + }, + { + query: 'my_crate 中文宏!', + elems: [{ + name: "my_crate 中文宏", + fullPath: ["my_crate", "中文宏"], + pathWithoutLast: ["my_crate"], + pathLast: "中文宏", + generics: [], + typeFilter: 16, + }], + foundElems: 1, + original: "my_crate 中文宏!", + returned: [], + userQuery: "my_crate 中文宏!", + error: null, + }, + { + query: '非法符号——', + elems: [], + foundElems: 0, + original: "非法符号——", + returned: [], + userQuery: "非法符号——", + error: "Unexpected `—` after `号` (not a valid identifier)", + } +] +const EXPECTED = [ + { + query: '加法', + others: [ + { + name: "add", + path: "non_english_identifier", + is_alias: true, + alias: "加法", + href: "../non_english_identifier/macro.add.html" + }, + { + name: "add", + path: "non_english_identifier", + is_alias: true, + alias: "加法", + href: "../non_english_identifier/fn.add.html" + }, + { + name: "加法", + path: "non_english_identifier", + href: "../non_english_identifier/trait.加法.html", + desc: "Add" + }, + { + name: "中文名称的加法宏", + path: "non_english_identifier", + href: "../non_english_identifier/macro.中文名称的加法宏.html", + }, + { + name: "中文名称的加法API", + path: "non_english_identifier", + href: "../non_english_identifier/fn.中文名称的加法API.html", + }], + in_args: [{ + name: "加上", + path: "non_english_identifier::加法", + href: "../non_english_identifier/trait.加法.html#tymethod.加上", + }], + returned: [], + }, + { // Extensive type-based search is still buggy, experimental & work-in-progress. + query: '可迭代->可选', + others: [{ + name: "总计", + path: "non_english_identifier", + href: "../non_english_identifier/fn.总计.html", + desc: "“sum”" + }], + in_args: [], + returned: [], + }, +]; diff --git a/tests/rustdoc-js/non-english-identifier.rs b/tests/rustdoc-js/non-english-identifier.rs new file mode 100644 index 00000000000..70b5141472c --- /dev/null +++ b/tests/rustdoc-js/non-english-identifier.rs @@ -0,0 +1,47 @@ +#[doc(alias = "加法")] +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +pub fn 中文名称的加法API(left: usize, right: usize) -> usize { + left + right +} + +#[macro_export] +macro_rules! 中文名称的加法宏 { + ($left:expr, $right:expr) => { + ($left) + ($right) + }; +} + +#[doc(alias = "加法")] +#[macro_export] +macro_rules! add { + ($left:expr, $right:expr) => { + ($left) + ($right) + }; +} + +/// Add +pub trait 加法<类型> { + type 结果; + fn 加上(self, 被加数: 类型) -> Self::结果; +} + +/// IntoIterator +pub trait 可迭代 { + type 项; + type 转为迭代器: Iterator<Item = Self::项>; + fn 迭代(self) -> Self::转为迭代器; +} + +pub type 可选<类型> = Option<类型>; + +/// "sum" +pub fn 总计<集合, 个体>(容器: 集合) -> 可选<集合::项> +where + 集合: 可迭代<项 = 个体>, + 个体: 加法<个体, 结果 = 个体>, +{ + 容器.迭代().reduce(|累计值, 当前值| 累计值.加上(当前值)) +} diff --git a/tests/rustdoc-js/path-maxeditdistance.rs b/tests/rustdoc-js/path-maxeditdistance.rs index 3861280d59b..88af4f48774 100644 --- a/tests/rustdoc-js/path-maxeditdistance.rs +++ b/tests/rustdoc-js/path-maxeditdistance.rs @@ -1,3 +1,3 @@ -#![crate_name="abracadabra"] +#![crate_name = "abracadabra"] pub struct HocusPocusPrestidigitation; diff --git a/tests/rustdoc-js/prototype.rs b/tests/rustdoc-js/prototype.rs index 5f6d73cc196..77553561238 100644 --- a/tests/rustdoc-js/prototype.rs +++ b/tests/rustdoc-js/prototype.rs @@ -1,4 +1,4 @@ // The alias needed to be there to reproduce the bug // that used to be here. -#[doc(alias="other_alias")] +#[doc(alias = "other_alias")] pub fn something_else() {} diff --git a/tests/rustdoc-js/reexport-dedup-macro.rs b/tests/rustdoc-js/reexport-dedup-macro.rs index 3d18da3951c..f70b9c3d733 100644 --- a/tests/rustdoc-js/reexport-dedup-macro.rs +++ b/tests/rustdoc-js/reexport-dedup-macro.rs @@ -1,5 +1,5 @@ //@ aux-crate: macro_in_module=macro-in-module.rs -#![crate_name="foo"] +#![crate_name = "foo"] extern crate macro_in_module; // Test case based on the relationship between alloc and std. diff --git a/tests/rustdoc-js/reexport-dedup-method.rs b/tests/rustdoc-js/reexport-dedup-method.rs index 5dbd66e9c8e..c00df094d7a 100644 --- a/tests/rustdoc-js/reexport-dedup-method.rs +++ b/tests/rustdoc-js/reexport-dedup-method.rs @@ -1,5 +1,5 @@ // This test enforces that the (renamed) reexports are present in the search results. -#![crate_name="foo"] +#![crate_name = "foo"] pub mod fmt { pub struct Subscriber; @@ -14,5 +14,5 @@ mod foo { } } -pub use foo::AnotherOne; pub use fmt::Subscriber; +pub use foo::AnotherOne; diff --git a/tests/rustdoc-js/reexport-dedup.rs b/tests/rustdoc-js/reexport-dedup.rs index 40aea963303..83c23d5c366 100644 --- a/tests/rustdoc-js/reexport-dedup.rs +++ b/tests/rustdoc-js/reexport-dedup.rs @@ -1,5 +1,5 @@ // This test enforces that the (renamed) reexports are present in the search results. -#![crate_name="foo"] +#![crate_name = "foo"] pub mod fmt { pub struct Subscriber; @@ -8,5 +8,5 @@ mod foo { pub struct AnotherOne; } -pub use foo::AnotherOne; pub use fmt::Subscriber; +pub use foo::AnotherOne; diff --git a/tests/rustdoc-js/reexport.rs b/tests/rustdoc-js/reexport.rs index d51b7fb369c..0b3718cd9a3 100644 --- a/tests/rustdoc-js/reexport.rs +++ b/tests/rustdoc-js/reexport.rs @@ -9,5 +9,5 @@ mod foo { pub struct AnotherOne; } -pub use foo::AnotherOne; pub use fmt::Subscriber as FmtSubscriber; +pub use foo::AnotherOne; diff --git a/tests/rustdoc-js/reference.rs b/tests/rustdoc-js/reference.rs index 3a0a23c65d5..93b2a6df8e6 100644 --- a/tests/rustdoc-js/reference.rs +++ b/tests/rustdoc-js/reference.rs @@ -7,13 +7,17 @@ pub fn pinky(input: &usize, manage: usize) { pub struct Thumb; impl Thumb { - pub fn up(&self, finger: Thumb) { unimplemented!() } + pub fn up(&self, finger: Thumb) { + unimplemented!() + } } pub enum Index {} impl Index { - pub fn point(self, data: &Index) { unimplemented!() } + pub fn point(self, data: &Index) { + unimplemented!() + } } pub union Ring { @@ -22,11 +26,15 @@ pub union Ring { } impl Ring { - pub fn wear(&mut self, extra: &Ring) { unimplemented!() } + pub fn wear(&mut self, extra: &Ring) { + unimplemented!() + } } extern "C" { pub type Middle; } -pub fn show(left: &&mut Middle, right: &mut &Middle) { unimplemented!() } +pub fn show(left: &&mut Middle, right: &mut &Middle) { + unimplemented!() +} diff --git a/tests/rustdoc-js/slice-array.rs b/tests/rustdoc-js/slice-array.rs index 15ac4294f3d..e4e34a26fa2 100644 --- a/tests/rustdoc-js/slice-array.rs +++ b/tests/rustdoc-js/slice-array.rs @@ -3,12 +3,20 @@ pub struct Q; pub struct R<T>(T); // returns test -pub fn alef() -> &'static [R<P>] { loop {} } -pub fn bet() -> R<[Q; 32]> { loop {} } +pub fn alef() -> &'static [R<P>] { + loop {} +} +pub fn bet() -> R<[Q; 32]> { + loop {} +} // in_args test -pub fn alpha(_x: R<&'static [P]>) { loop {} } -pub fn beta(_x: [R<Q>; 32]) { loop {} } +pub fn alpha(_x: R<&'static [P]>) { + loop {} +} +pub fn beta(_x: [R<Q>; 32]) { + loop {} +} pub trait TraitCat {} pub trait TraitDog {} diff --git a/tests/rustdoc-js/struct-like-variant.rs b/tests/rustdoc-js/struct-like-variant.rs index 2f52a319ab9..aafde9957ff 100644 --- a/tests/rustdoc-js/struct-like-variant.rs +++ b/tests/rustdoc-js/struct-like-variant.rs @@ -3,6 +3,6 @@ pub enum Enum { Bar { /// This is a name. - name: String - } + name: String, + }, } diff --git a/tests/rustdoc-js/summaries.rs b/tests/rustdoc-js/summaries.rs index 1ee1c34aa15..9e8fc820245 100644 --- a/tests/rustdoc-js/summaries.rs +++ b/tests/rustdoc-js/summaries.rs @@ -1,6 +1,5 @@ #![crate_type = "lib"] #![crate_name = "summaries"] - #![allow(rustdoc::broken_intra_doc_links)] //! This *summary* has a [link], [`code`], and [`Sidebar2`] intra-doc. diff --git a/tests/rustdoc-js/tuple-unit.rs b/tests/rustdoc-js/tuple-unit.rs index 93f9a671cbc..4531545cf6c 100644 --- a/tests/rustdoc-js/tuple-unit.rs +++ b/tests/rustdoc-js/tuple-unit.rs @@ -3,16 +3,24 @@ pub struct Q; pub struct R<T>(T); // Checks that tuple and unit both work -pub fn side_effect() { } +pub fn side_effect() {} // Check a non-tuple -pub fn not_tuple() -> P { loop {} } +pub fn not_tuple() -> P { + loop {} +} // Check a 1-tuple -pub fn one() -> (P,) { loop {} } +pub fn one() -> (P,) { + loop {} +} // Check a 2-tuple -pub fn two() -> (P,P) { loop {} } +pub fn two() -> (P, P) { + loop {} +} // Check a nested tuple -pub fn nest() -> (Q, R<(u32,)>) { loop {} } +pub fn nest() -> (Q, R<(u32,)>) { + loop {} +} diff --git a/tests/rustdoc-js/type-parameters.rs b/tests/rustdoc-js/type-parameters.rs index cda5e26171f..0edbfbea178 100644 --- a/tests/rustdoc-js/type-parameters.rs +++ b/tests/rustdoc-js/type-parameters.rs @@ -1,15 +1,23 @@ -#![crate_name="foo"] +#![crate_name = "foo"] pub trait Some {} impl Some for () {} pub trait Other {} impl Other for () {} -pub fn alef<T: Some>() -> T { loop {} } -pub fn alpha() -> impl Some { } +pub fn alef<T: Some>() -> T { + loop {} +} +pub fn alpha() -> impl Some {} -pub fn bet<T, U>(t: T) -> U { loop {} } +pub fn bet<T, U>(t: T) -> U { + loop {} +} pub fn beta<T>(t: T) -> T {} -pub fn other<T: Other, U: Other>(t: T, u: U) { loop {} } -pub fn alternate<T: Other>(t: T, u: T) { loop {} } +pub fn other<T: Other, U: Other>(t: T, u: U) { + loop {} +} +pub fn alternate<T: Other>(t: T, u: T) { + loop {} +} diff --git a/tests/rustdoc-js/underscoredtype.js b/tests/rustdoc-js/underscoredtype.js new file mode 100644 index 00000000000..06e3b07b096 --- /dev/null +++ b/tests/rustdoc-js/underscoredtype.js @@ -0,0 +1,62 @@ +const EXPECTED = [ + { + 'query': 'pid_t', + 'correction': null, + 'proposeCorrectionFrom': null, + 'proposeCorrectionTo': null, + 'others': [ + { 'path': 'underscoredtype::unix', 'name': 'pid_t' }, + ], + 'returned': [ + { 'path': 'underscoredtype::unix', 'name': 'set_pid' }, + ], + 'returned': [ + { 'path': 'underscoredtype::unix', 'name': 'get_pid' }, + ], + }, + { + 'query': 'pidt', + 'correction': 'pid_t', + 'proposeCorrectionFrom': null, + 'proposeCorrectionTo': null, + 'others': [ + { 'path': 'underscoredtype::unix', 'name': 'pid_t' }, + ], + 'returned': [ + { 'path': 'underscoredtype::unix', 'name': 'set_pid' }, + ], + 'returned': [ + { 'path': 'underscoredtype::unix', 'name': 'get_pid' }, + ], + }, + { + 'query': 'unix::pid_t', + 'correction': null, + 'proposeCorrectionFrom': null, + 'proposeCorrectionTo': null, + 'others': [ + { 'path': 'underscoredtype::unix', 'name': 'pid_t' }, + ], + 'returned': [ + { 'path': 'underscoredtype::unix', 'name': 'set_pid' }, + ], + 'returned': [ + { 'path': 'underscoredtype::unix', 'name': 'get_pid' }, + ], + }, + { + 'query': 'unix::pidt', + 'correction': 'pid_t', + 'proposeCorrectionFrom': null, + 'proposeCorrectionTo': null, + 'others': [ + { 'path': 'underscoredtype::unix', 'name': 'pid_t' }, + ], + 'returned': [ + { 'path': 'underscoredtype::unix', 'name': 'set_pid' }, + ], + 'returned': [ + { 'path': 'underscoredtype::unix', 'name': 'get_pid' }, + ], + }, +]; diff --git a/tests/rustdoc-js/underscoredtype.rs b/tests/rustdoc-js/underscoredtype.rs new file mode 100644 index 00000000000..83c532cf855 --- /dev/null +++ b/tests/rustdoc-js/underscoredtype.rs @@ -0,0 +1,8 @@ +pub mod unix { + #[allow(non_camel_case_types)] + pub type pid_t = i32; + pub fn get_pid() -> pid_t { + 0 + } + pub fn set_pid(_: pid_t) {} +} diff --git a/tests/rustdoc-js/where-clause.rs b/tests/rustdoc-js/where-clause.rs index 56c01019fb6..c0fede1cfd5 100644 --- a/tests/rustdoc-js/where-clause.rs +++ b/tests/rustdoc-js/where-clause.rs @@ -4,27 +4,46 @@ pub trait Trait<T> { fn thank_you(x: T); } -pub fn abracadabra<X>(_: X) where X: Trait<Nested> {} +pub fn abracadabra<X>(_: X) +where + X: Trait<Nested>, +{ +} -pub fn alacazam<X>() -> X where X: Trait<Nested> {} +pub fn alacazam<X>() -> X +where + X: Trait<Nested>, +{ +} pub trait T1 {} pub trait T2<'a, T> { fn please(_: &'a T); } -pub fn presto<A, B>(_: A, _: B) where A: T1, B: for <'b> T2<'b, Nested> {} +pub fn presto<A, B>(_: A, _: B) +where + A: T1, + B: for<'b> T2<'b, Nested>, +{ +} pub trait Shazam {} -pub fn bippety<X>() -> &'static X where X: Shazam { +pub fn bippety<X>() -> &'static X +where + X: Shazam, +{ panic!() } pub struct Drizzel<T>(T); impl<T> Drizzel<T> { - pub fn boppety(&self) -> &T where T: Shazam { + pub fn boppety(&self) -> &T + where + T: Shazam, + { panic!(); } } diff --git a/tests/rustdoc-json/lifetime/longest.rs b/tests/rustdoc-json/lifetime/longest.rs index 419b0b4fcab..dccad41a861 100644 --- a/tests/rustdoc-json/lifetime/longest.rs +++ b/tests/rustdoc-json/lifetime/longest.rs @@ -23,9 +23,5 @@ // @is "$.index[*][?(@.name=='longest')].inner.function.decl.output.borrowed_ref.type.primitive" \"str\" pub fn longest<'a>(l: &'a str, r: &'a str) -> &'a str { - if l.len() > r.len() { - l - } else { - r - } + if l.len() > r.len() { l } else { r } } diff --git a/tests/rustdoc-json/non_lifetime_binders.rs b/tests/rustdoc-json/non_lifetime_binders.rs index d925fcd5221..6f0732646ca 100644 --- a/tests/rustdoc-json/non_lifetime_binders.rs +++ b/tests/rustdoc-json/non_lifetime_binders.rs @@ -12,4 +12,8 @@ pub struct Wrapper<T_>(std::marker::PhantomData<T_>); // @is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[0].kind" '{ "lifetime": { "outlives": [] } }' // @is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[1].name" \"T\" // @is "$.index[*][?(@.name=='foo')].inner.function.generics.where_predicates[0].bound_predicate.generic_params[1].kind" '{ "type": { "bounds": [], "default": null, "synthetic": false } }' -pub fn foo() where for<'a, T> &'a Wrapper<T>: Trait {} +pub fn foo() +where + for<'a, T> &'a Wrapper<T>: Trait, +{ +} diff --git a/tests/rustdoc-json/output_generics.rs b/tests/rustdoc-json/output_generics.rs index d421eafbb47..e9df64b79e3 100644 --- a/tests/rustdoc-json/output_generics.rs +++ b/tests/rustdoc-json/output_generics.rs @@ -16,12 +16,19 @@ pub trait Trait<T> { fn handle(value: T) -> Self; } -impl<T, U> Trait<U> for T where T: From<U> { - fn handle(_: U) -> Self { unimplemented!() } +impl<T, U> Trait<U> for T +where + T: From<U>, +{ + fn handle(_: U) -> Self { + unimplemented!() + } } impl<'a, R> Trait<&'a mut Events<R>> for Other { - fn handle(_: &'a mut Events<R>) -> Self { unimplemented!() } + fn handle(_: &'a mut Events<R>) -> Self { + unimplemented!() + } } fn this_compiles<'a, R>(value: &'a mut Events<R>) { diff --git a/tests/rustdoc-json/type/extern.rs b/tests/rustdoc-json/type/extern.rs index c30146ce9e0..59e099ec9fc 100644 --- a/tests/rustdoc-json/type/extern.rs +++ b/tests/rustdoc-json/type/extern.rs @@ -1,6 +1,6 @@ #![feature(extern_types)] -extern { +extern "C" { /// No inner information pub type Foo; } diff --git a/tests/rustdoc-json/unions/impl.rs b/tests/rustdoc-json/unions/impl.rs index 7456892df1b..1515f7d9397 100644 --- a/tests/rustdoc-json/unions/impl.rs +++ b/tests/rustdoc-json/unions/impl.rs @@ -4,7 +4,7 @@ // @has "$.index[*][?(@.name=='Ux')].inner.union" pub union Ux { a: u32, - b: u64 + b: u64, } // @is "$.index[*][?(@.name=='Num')].visibility" \"public\" diff --git a/tests/rustdoc-json/unions/union.rs b/tests/rustdoc-json/unions/union.rs index 22b70e1ce8c..1089d9c4558 100644 --- a/tests/rustdoc-json/unions/union.rs +++ b/tests/rustdoc-json/unions/union.rs @@ -7,7 +7,6 @@ pub union Union { float: f32, } - // @has "$.index[*][?(@.name=='make_int_union')].inner.function.decl.output.resolved_path" // @is "$.index[*][?(@.name=='make_int_union')].inner.function.decl.output.resolved_path.id" $Union pub fn make_int_union(int: i32) -> Union { diff --git a/tests/rustdoc-ui/ice-blanket-impl-119792.rs b/tests/rustdoc-ui/ice-blanket-impl-119792.rs new file mode 100644 index 00000000000..90f0ea8469b --- /dev/null +++ b/tests/rustdoc-ui/ice-blanket-impl-119792.rs @@ -0,0 +1,19 @@ +//@ check-pass +// https://github.com/rust-lang/rust/issues/119792 + +struct Wrapper<T>(T); + +trait Div<Rhs> {} +trait Mul<Rhs> { + type Output; +} + +impl<T> Mul<T> for Wrapper<T> { + type Output = (); +} + +impl<T> Div<Self> for Wrapper<T> {} + +pub trait NumOps<Rhs> {} + +impl<T, Rhs> NumOps<Rhs> for T where T: Mul<Rhs, Output = ()> + Div<Rhs> {} diff --git a/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.rs b/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.rs new file mode 100644 index 00000000000..2b220370d77 --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.rs @@ -0,0 +1,14 @@ +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +//@ failure-status: 101 +//@ compile-flags:--test -Z unstable-options --remap-path-prefix={{src-base}}=remapped_path --test-args --test-threads=1 +//@ rustc-env:RUST_BACKTRACE=0 +//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout-test "exit (status|code): 101" -> "exit status: 101" + +// doctest fails at runtime +/// ``` +/// panic!("oh no"); +/// ``` +pub struct SomeStruct; diff --git a/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.stdout b/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.stdout new file mode 100644 index 00000000000..2102e2c3891 --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.stdout @@ -0,0 +1,21 @@ + +running 1 test +test remapped_path/remap-path-prefix-failed-doctest-output.rs - SomeStruct (line 11) ... FAILED + +failures: + +---- remapped_path/remap-path-prefix-failed-doctest-output.rs - SomeStruct (line 11) stdout ---- +Test executable failed (exit status: 101). + +stderr: +thread 'main' panicked at remapped_path/remap-path-prefix-failed-doctest-output.rs:3:1: +oh no +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + + + +failures: + remapped_path/remap-path-prefix-failed-doctest-output.rs - SomeStruct (line 11) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.rs b/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.rs new file mode 100644 index 00000000000..2e023e32d7a --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.rs @@ -0,0 +1,13 @@ +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +//@ failure-status: 101 +//@ compile-flags:--test -Z unstable-options --remap-path-prefix={{src-base}}=remapped_path --test-args --test-threads=1 +//@ rustc-env:RUST_BACKTRACE=0 +//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +// doctest fails to compile +/// ``` +/// this is not real code +/// ``` +pub struct SomeStruct; diff --git a/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout b/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout new file mode 100644 index 00000000000..a05b5169989 --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout @@ -0,0 +1,22 @@ + +running 1 test +test remapped_path/remap-path-prefix-invalid-doctest.rs - SomeStruct (line 10) ... FAILED + +failures: + +---- remapped_path/remap-path-prefix-invalid-doctest.rs - SomeStruct (line 10) stdout ---- +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `is` + --> remapped_path/remap-path-prefix-invalid-doctest.rs:11:6 + | +LL | this is not real code + | ^^ expected one of 8 possible tokens + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + remapped_path/remap-path-prefix-invalid-doctest.rs - SomeStruct (line 10) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.rs b/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.rs new file mode 100644 index 00000000000..c58f3faeb53 --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.rs @@ -0,0 +1,14 @@ +//@ check-pass +//@ check-run-results + +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +//@ compile-flags:--test -Z unstable-options --remap-path-prefix={{src-base}}=remapped_path --test-args --test-threads=1 +//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +// doctest passes at runtime +/// ``` +/// assert!(true); +/// ``` +pub struct SomeStruct; diff --git a/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.stdout b/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.stdout new file mode 100644 index 00000000000..8ffb5694885 --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.stdout @@ -0,0 +1,6 @@ + +running 1 test +test remapped_path/remap-path-prefix-passed-doctest-output.rs - SomeStruct (line 11) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/unable-fulfill-trait.rs b/tests/rustdoc-ui/unable-fulfill-trait.rs index a69f74b09ac..f3b6256346f 100644 --- a/tests/rustdoc-ui/unable-fulfill-trait.rs +++ b/tests/rustdoc-ui/unable-fulfill-trait.rs @@ -1,13 +1,16 @@ // This test ensures that it's not crashing rustdoc. pub struct Foo<'a, 'b, T> { - field1: dyn Bar<'a, 'b,>, + field1: dyn Bar<'a, 'b>, //~^ ERROR //~| ERROR + //~| ERROR } pub trait Bar<'x, 's, U> - where U: 'x, - Self:'x, - Self:'s -{} +where + U: 'x, + Self: 'x, + Self: 's, +{ +} diff --git a/tests/rustdoc-ui/unable-fulfill-trait.stderr b/tests/rustdoc-ui/unable-fulfill-trait.stderr index 72f35cb9224..40d103f2a62 100644 --- a/tests/rustdoc-ui/unable-fulfill-trait.stderr +++ b/tests/rustdoc-ui/unable-fulfill-trait.stderr @@ -1,26 +1,43 @@ error[E0107]: trait takes 1 generic argument but 0 generic arguments were supplied --> $DIR/unable-fulfill-trait.rs:4:17 | -LL | field1: dyn Bar<'a, 'b,>, +LL | field1: dyn Bar<'a, 'b>, | ^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `U` - --> $DIR/unable-fulfill-trait.rs:9:11 + --> $DIR/unable-fulfill-trait.rs:10:11 | LL | pub trait Bar<'x, 's, U> | ^^^ - help: add missing generic argument | -LL | field1: dyn Bar<'a, 'b, U,>, +LL | field1: dyn Bar<'a, 'b, U>, | +++ error[E0227]: ambiguous lifetime bound, explicit lifetime bound required --> $DIR/unable-fulfill-trait.rs:4:13 | -LL | field1: dyn Bar<'a, 'b,>, - | ^^^^^^^^^^^^^^^^ +LL | field1: dyn Bar<'a, 'b>, + | ^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error[E0478]: lifetime bound not satisfied + --> $DIR/unable-fulfill-trait.rs:4:13 + | +LL | field1: dyn Bar<'a, 'b>, + | ^^^^^^^^^^^^^^^ + | +note: lifetime parameter instantiated with the lifetime `'b` as defined here + --> $DIR/unable-fulfill-trait.rs:3:20 + | +LL | pub struct Foo<'a, 'b, T> { + | ^^ +note: but lifetime parameter must outlive the lifetime `'a` as defined here + --> $DIR/unable-fulfill-trait.rs:3:16 + | +LL | pub struct Foo<'a, 'b, T> { + | ^^ + +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0107, E0227. +Some errors have detailed explanations: E0107, E0227, E0478. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/rustdoc/async-fn.rs b/tests/rustdoc/async-fn.rs index 010263f6ad3..4de5d8575b0 100644 --- a/tests/rustdoc/async-fn.rs +++ b/tests/rustdoc/async-fn.rs @@ -79,7 +79,7 @@ struct AsyncFdReadyGuard<'a, T> { x: &'a T } impl Foo { // @has async_fn/struct.Foo.html - // @has - '//*[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar ) -> impl Iterator<Item = &usize>' + // @has - '//*[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar, ) -> impl Iterator<Item = &usize>' pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> { [0].iter() } diff --git a/tests/rustdoc/decl-line-wrapping-empty-arg-list.decl.html b/tests/rustdoc/decl-line-wrapping-empty-arg-list.decl.html index 29c08c5bd5d..12c6bc214a7 100644 --- a/tests/rustdoc/decl-line-wrapping-empty-arg-list.decl.html +++ b/tests/rustdoc/decl-line-wrapping-empty-arg-list.decl.html @@ -1,2 +1 @@ -<pre class="rust item-decl"><code>pub fn create( -) -> <a class="struct" href="struct.Padding00000000000000000000000000000000000000000000000000000000000000000000000000000000.html" title="struct decl_line_wrapping_empty_arg_list::Padding00000000000000000000000000000000000000000000000000000000000000000000000000000000">Padding00000000000000000000000000000000000000000000000000000000000000000000000000000000</a></code></pre> \ No newline at end of file +<pre class="rust item-decl"><code>pub fn create() -> <a class="struct" href="struct.Padding00000000000000000000000000000000000000000000000000000000000000000000000000000000.html" title="struct decl_line_wrapping_empty_arg_list::Padding00000000000000000000000000000000000000000000000000000000000000000000000000000000">Padding00000000000000000000000000000000000000000000000000000000000000000000000000000000</a></code></pre> \ No newline at end of file diff --git a/tests/rustdoc/decl-trailing-whitespace.declaration.html b/tests/rustdoc/decl-trailing-whitespace.declaration.html index 59c318c16f3..0cc3f0fa244 100644 --- a/tests/rustdoc/decl-trailing-whitespace.declaration.html +++ b/tests/rustdoc/decl-trailing-whitespace.declaration.html @@ -3,7 +3,7 @@ fn <a href="#tymethod.poll_write" class="fn">poll_write</a>( self, cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>, - buf: &mut [<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>] + buf: &mut [<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>], ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>; <span class="item-spacer" /> fn <a href="#tymethod.poll_flush" class="fn">poll_flush</a>(self, cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>; <span class="item-spacer" /> fn <a href="#tymethod.poll_close" class="fn">poll_close</a>(self, cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.unit.html">()</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>>; @@ -12,6 +12,6 @@ fn <a href="#method.poll_write_vectored" class="fn">poll_write_vectored</a>( self, cx: &mut <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="struct" href="{{channel}}/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>>, - bufs: &[<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>] + bufs: &[<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>], ) -> <a class="enum" href="{{channel}}/core/option/enum.Option.html" title="enum core::option::Option">Option</a><<a class="enum" href="{{channel}}/core/result/enum.Result.html" title="enum core::result::Result">Result</a><<a class="primitive" href="{{channel}}/std/primitive.usize.html">usize</a>, <a class="struct" href="struct.Error.html" title="struct foo::Error">Error</a>>> { ... } }</code> \ No newline at end of file diff --git a/tests/rustdoc/inline_cross/impl_trait.rs b/tests/rustdoc/inline_cross/impl_trait.rs index 47e2c9dc76b..19d1673f2eb 100644 --- a/tests/rustdoc/inline_cross/impl_trait.rs +++ b/tests/rustdoc/inline_cross/impl_trait.rs @@ -11,7 +11,7 @@ pub use impl_trait_aux::func; // @has impl_trait/fn.func2.html // @has - '//pre[@class="rust item-decl"]' "func2<T>(" // @has - '//pre[@class="rust item-decl"]' "_x: impl Deref<Target = Option<T>> + Iterator<Item = T>," -// @has - '//pre[@class="rust item-decl"]' "_y: impl Iterator<Item = u8> )" +// @has - '//pre[@class="rust item-decl"]' "_y: impl Iterator<Item = u8>, )" // @!has - '//pre[@class="rust item-decl"]' 'where' pub use impl_trait_aux::func2; diff --git a/tests/rustdoc/line-breaks.rs b/tests/rustdoc/line-breaks.rs index 21aa3a03ce4..0f760d51973 100644 --- a/tests/rustdoc/line-breaks.rs +++ b/tests/rustdoc/line-breaks.rs @@ -6,7 +6,7 @@ use std::ops::Add; // @matches foo/fn.function_with_a_really_long_name.html '//*[@class="rust item-decl"]//code' "\ // function_with_a_really_long_name\(\n\ // \ parameter_one: i32,\n\ -// \ parameter_two: i32\n\ +// \ parameter_two: i32,\n\ // \) -> Option<i32>$" pub fn function_with_a_really_long_name(parameter_one: i32, parameter_two: i32) -> Option<i32> { Some(parameter_one + parameter_two) diff --git a/tests/rustdoc/reexports-priv.rs b/tests/rustdoc/reexports-priv.rs index 1eee262d233..97318a01410 100644 --- a/tests/rustdoc/reexports-priv.rs +++ b/tests/rustdoc/reexports-priv.rs @@ -98,7 +98,7 @@ pub mod outer { pub use reexports::foo; // @has 'foo/outer/inner/fn.foo_crate.html' '//pre[@class="rust item-decl"]' 'pub(crate) fn foo_crate()' pub(crate) use reexports::foo_crate; - // @has 'foo/outer/inner/fn.foo_super.html' '//pre[@class="rust item-decl"]' 'pub(in outer) fn foo_super( )' + // @has 'foo/outer/inner/fn.foo_super.html' '//pre[@class="rust item-decl"]' 'pub(in outer) fn foo_super()' pub(super) use::reexports::foo_super; // @!has 'foo/outer/inner/fn.foo_self.html' pub(self) use reexports::foo_self; diff --git a/tests/run-make-fulldeps/obtain-borrowck/test.rs b/tests/ui-fulldeps/auxiliary/obtain-borrowck-input.rs index f7b4b41feaf..7213e06792a 100644 --- a/tests/run-make-fulldeps/obtain-borrowck/test.rs +++ b/tests/ui-fulldeps/auxiliary/obtain-borrowck-input.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + trait X { fn provided(&self) -> usize { 5 diff --git a/tests/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs index 28a1e27cccc..f273bbc99a8 100644 --- a/tests/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs +++ b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs @@ -1,3 +1,5 @@ +//@ edition: 2021 + #![feature(rustc_private)] #![deny(warnings)] @@ -27,7 +29,9 @@ use std::any::Any; struct TheBackend; impl CodegenBackend for TheBackend { - fn locale_resource(&self) -> &'static str { "" } + fn locale_resource(&self) -> &'static str { + "" + } fn codegen_crate<'a, 'tcx>( &self, @@ -62,7 +66,10 @@ impl CodegenBackend for TheBackend { codegen_results: CodegenResults, outputs: &OutputFilenames, ) -> Result<(), ErrorGuaranteed> { - use rustc_session::{config::{CrateType, OutFileName}, output::out_filename}; + use rustc_session::{ + config::{CrateType, OutFileName}, + output::out_filename, + }; use std::io::Write; let crate_name = codegen_results.crate_info.local_crate_name; for &crate_type in sess.opts.crate_types.iter() { @@ -73,11 +80,11 @@ impl CodegenBackend for TheBackend { match output_name { OutFileName::Real(ref path) => { let mut out_file = ::std::fs::File::create(path).unwrap(); - write!(out_file, "This has been \"compiled\" successfully.").unwrap(); + writeln!(out_file, "This has been 'compiled' successfully.").unwrap(); } OutFileName::Stdout => { let mut stdout = std::io::stdout(); - write!(stdout, "This has been \"compiled\" successfully.").unwrap(); + writeln!(stdout, "This has been 'compiled' successfully.").unwrap(); } } } diff --git a/tests/ui-fulldeps/codegen-backend/hotplug.bindep.stdout b/tests/ui-fulldeps/codegen-backend/hotplug.bindep.stdout new file mode 100644 index 00000000000..4d58fd503d0 --- /dev/null +++ b/tests/ui-fulldeps/codegen-backend/hotplug.bindep.stdout @@ -0,0 +1,4 @@ +$TEST_BUILD_DIR/codegen-backend/hotplug.bindep/libhotplug.rlib: $DIR/hotplug.rs $TEST_BUILD_DIR/codegen-backend/hotplug.bindep/auxiliary/libthe_backend.so + +$DIR/hotplug.rs: +$TEST_BUILD_DIR/codegen-backend/hotplug.bindep/auxiliary/libthe_backend.so: diff --git a/tests/ui-fulldeps/codegen-backend/hotplug.dep.stdout b/tests/ui-fulldeps/codegen-backend/hotplug.dep.stdout new file mode 100644 index 00000000000..48b7534d8fa --- /dev/null +++ b/tests/ui-fulldeps/codegen-backend/hotplug.dep.stdout @@ -0,0 +1,3 @@ +$TEST_BUILD_DIR/codegen-backend/hotplug.dep/libhotplug.rlib: $DIR/hotplug.rs + +$DIR/hotplug.rs: diff --git a/tests/ui-fulldeps/codegen-backend/hotplug.normal.stdout b/tests/ui-fulldeps/codegen-backend/hotplug.normal.stdout new file mode 100644 index 00000000000..1aa032de9e4 --- /dev/null +++ b/tests/ui-fulldeps/codegen-backend/hotplug.normal.stdout @@ -0,0 +1 @@ +This has been 'compiled' successfully. diff --git a/tests/ui-fulldeps/codegen-backend/hotplug.rs b/tests/ui-fulldeps/codegen-backend/hotplug.rs new file mode 100644 index 00000000000..dc0fb3f9efd --- /dev/null +++ b/tests/ui-fulldeps/codegen-backend/hotplug.rs @@ -0,0 +1,20 @@ +//@ edition: 2021 +//@ build-pass +//@ ignore-stage1 (requires matching sysroot built with in-tree compiler) + +//@ aux-codegen-backend: the_backend.rs +//@ normalize-stdout-test: "libthe_backend.dylib" -> "libthe_backend.so" +//@ normalize-stdout-test: "the_backend.dll" -> "libthe_backend.so" + +//@ revisions: normal dep bindep +//@ compile-flags: --crate-type=lib +//@ [normal] compile-flags: --emit=link=- +//@ [dep] compile-flags: --emit=link,dep-info=- +//@ [bindep] compile-flags: --emit=link,dep-info=- -Zbinary-dep-depinfo + +#![feature(no_core)] +#![no_core] + +// This test both exists as a check that -Zcodegen-backend is capable of loading external codegen +// backends and that this external codegen backend is only included in the dep info if +// -Zbinary-dep-depinfo is used. diff --git a/tests/ui-fulldeps/mod_dir_path_canonicalized.rs b/tests/ui-fulldeps/mod_dir_path_canonicalized.rs index ef70e64ed7e..99cb5fc5aa1 100644 --- a/tests/ui-fulldeps/mod_dir_path_canonicalized.rs +++ b/tests/ui-fulldeps/mod_dir_path_canonicalized.rs @@ -16,7 +16,7 @@ extern crate rustc_span; #[allow(unused_extern_crates)] extern crate rustc_driver; -use rustc_parse::new_parser_from_file; +use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use std::path::Path; @@ -34,6 +34,6 @@ fn parse() { let path = Path::new(file!()); let path = path.canonicalize().unwrap(); - let mut parser = new_parser_from_file(&psess, &path, None); + let mut parser = unwrap_or_emit_fatal(new_parser_from_file(&psess, &path, None)); let _ = parser.parse_crate_mod(); } diff --git a/tests/run-make-fulldeps/obtain-borrowck/driver.rs b/tests/ui-fulldeps/obtain-borrowck.rs index e67ec8690f8..e6c703addd9 100644 --- a/tests/run-make-fulldeps/obtain-borrowck/driver.rs +++ b/tests/ui-fulldeps/obtain-borrowck.rs @@ -1,3 +1,10 @@ +//@ edition: 2021 +//@ run-pass +//@ check-run-results +//@ run-flags: --sysroot {{sysroot-base}} --edition=2021 {{src-base}}/auxiliary/obtain-borrowck-input.rs +//@ ignore-stage1 (requires matching sysroot built with in-tree compiler) +// ignore-tidy-linelength + #![feature(rustc_private)] //! This program implements a rustc driver that retrieves MIR bodies with diff --git a/tests/run-make-fulldeps/obtain-borrowck/output.stdout b/tests/ui-fulldeps/obtain-borrowck.run.stdout index e011622e6b2..e011622e6b2 100644 --- a/tests/run-make-fulldeps/obtain-borrowck/output.stdout +++ b/tests/ui-fulldeps/obtain-borrowck.run.stdout diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs index 2b1fec94387..762ad0b79ec 100644 --- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs @@ -36,7 +36,7 @@ use rustc_ast::mut_visit::{visit_clobber, MutVisitor}; use rustc_ast::ptr::P; use rustc_ast::*; use rustc_ast_pretty::pprust; -use rustc_parse::new_parser_from_source_str; +use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::parse::ParseSess; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; @@ -46,8 +46,9 @@ use thin_vec::{thin_vec, ThinVec}; fn parse_expr(psess: &ParseSess, src: &str) -> Option<P<Expr>> { let src_as_string = src.to_string(); - let mut p = - new_parser_from_source_str(psess, FileName::Custom(src_as_string.clone()), src_as_string); + let mut p = unwrap_or_emit_fatal( + new_parser_from_source_str(psess, FileName::Custom(src_as_string.clone()), src_as_string) + ); p.parse_expr().map_err(|e| e.cancel()).ok() } diff --git a/tests/run-make-fulldeps/issue-19371/foo.rs b/tests/ui-fulldeps/run-compiler-twice.rs index 327c99a02c6..02748626723 100644 --- a/tests/run-make-fulldeps/issue-19371/foo.rs +++ b/tests/ui-fulldeps/run-compiler-twice.rs @@ -1,3 +1,13 @@ +//@ edition: 2021 +//@ run-pass +//@ run-flags: {{sysroot-base}} {{target-linker}} +//@ ignore-stage1 (requires matching sysroot built with in-tree compiler) + +// Regression test for <https://github.com/rust-lang/rust/issues/19371>. +// +// This test ensures that `compile_input` can be called twice in one task +// without causing a panic. + #![feature(rustc_private)] extern crate rustc_driver; @@ -5,12 +15,12 @@ extern crate rustc_interface; extern crate rustc_session; extern crate rustc_span; +use std::path::{Path, PathBuf}; + use rustc_interface::interface; use rustc_session::config::{Input, Options, OutFileName, OutputType, OutputTypes}; use rustc_span::FileName; -use std::path::PathBuf; - fn main() { let src = r#" fn main() {} @@ -18,28 +28,28 @@ fn main() { let args: Vec<String> = std::env::args().collect(); - if args.len() < 4 { - panic!("expected rustc path"); + if args.len() < 2 { + panic!("expected sysroot (and optional linker)"); } - let tmpdir = PathBuf::from(&args[1]); - - let mut sysroot = PathBuf::from(&args[3]); - sysroot.pop(); - sysroot.pop(); + let sysroot = PathBuf::from(&args[1]); + let linker = args.get(2).map(PathBuf::from); - compile(src.to_string(), tmpdir.join("out"), sysroot.clone()); + // compiletest sets the current dir to `output_base_dir` when running. + let tmpdir = std::env::current_dir().unwrap().join("tmp"); + std::fs::create_dir_all(&tmpdir).unwrap(); - compile(src.to_string(), tmpdir.join("out"), sysroot.clone()); + compile(src.to_string(), tmpdir.join("out"), sysroot.clone(), linker.as_deref()); + compile(src.to_string(), tmpdir.join("out"), sysroot.clone(), linker.as_deref()); } -fn compile(code: String, output: PathBuf, sysroot: PathBuf) { +fn compile(code: String, output: PathBuf, sysroot: PathBuf, linker: Option<&Path>) { let mut opts = Options::default(); opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]); opts.maybe_sysroot = Some(sysroot); - if let Ok(linker) = std::env::var("RUSTC_LINKER") { - opts.cg.linker = Some(linker.into()); + if let Some(linker) = linker { + opts.cg.linker = Some(linker.to_owned()); } let name = FileName::anon_source_code(&code); diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs index 218c7b3e386..f971426723f 100644 --- a/tests/ui-fulldeps/stable-mir/check_instance.rs +++ b/tests/ui-fulldeps/stable-mir/check_instance.rs @@ -33,7 +33,7 @@ fn test_stable_mir() -> ControlFlow<()> { // Get all items and split generic vs monomorphic items. let (generic, mono): (Vec<_>, Vec<_>) = items.into_iter().partition(|item| item.requires_monomorphization()); - assert_eq!(mono.len(), 3, "Expected 2 mono functions and one constant"); + assert_eq!(mono.len(), 4, "Expected 2 mono functions and one constant"); assert_eq!(generic.len(), 2, "Expected 2 generic functions"); // For all monomorphic items, get the correspondent instances. @@ -57,8 +57,9 @@ fn test_body(body: mir::Body) { for term in body.blocks.iter().map(|bb| &bb.terminator) { match &term.kind { Call { func, .. } => { - let TyKind::RigidTy(ty) = func.ty(body.locals()).unwrap().kind() else { unreachable! - () }; + let TyKind::RigidTy(ty) = func.ty(body.locals()).unwrap().kind() else { + unreachable!() + }; let RigidTy::FnDef(def, args) = ty else { unreachable!() }; let instance = Instance::resolve(def, &args).unwrap(); let mangled_name = instance.mangled_name(); @@ -102,6 +103,9 @@ fn generate_input(path: &str) -> std::io::Result<()> { write!( file, r#" + + struct Foo(()); + pub fn ty_param<T>(t: &T) -> T where T: Clone {{ t.clone() }} @@ -116,6 +120,7 @@ fn generate_input(path: &str) -> std::io::Result<()> { }} pub fn monomorphic() {{ + Foo(()); let v = vec![10]; let dup = ty_param(&v); assert_eq!(v, dup); diff --git a/tests/ui-fulldeps/stable-mir/check_transform.rs b/tests/ui-fulldeps/stable-mir/check_transform.rs index 6345ee24f78..b203e76e54f 100644 --- a/tests/ui-fulldeps/stable-mir/check_transform.rs +++ b/tests/ui-fulldeps/stable-mir/check_transform.rs @@ -22,7 +22,7 @@ use rustc_smir::rustc_internal; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::Instance; use stable_mir::mir::{Body, Constant, Operand, Rvalue, StatementKind, TerminatorKind}; -use stable_mir::ty::{Const, ConstantKind}; +use stable_mir::ty::{ConstantKind, MirConst}; use stable_mir::{CrateDef, CrateItems, ItemKind}; use std::convert::TryFrom; use std::io::Write; @@ -77,7 +77,7 @@ fn check_msg(body: &Body, expected: &str) { }; assert_eq!(alloc.provenance.ptrs.len(), 1); - let alloc_prov_id = alloc.provenance.ptrs[0].1 .0; + let alloc_prov_id = alloc.provenance.ptrs[0].1.0; let GlobalAlloc::Memory(val) = GlobalAlloc::from(alloc_prov_id) else { unreachable!() }; @@ -95,7 +95,7 @@ fn change_panic_msg(mut body: Body, new_msg: &str) -> Body { for bb in &mut body.blocks { match &mut bb.terminator.kind { TerminatorKind::Call { args, .. } => { - let new_const = Const::from_str(new_msg); + let new_const = MirConst::from_str(new_msg); args[0] = Operand::Constant(Constant { literal: new_const, span: bb.terminator.span, diff --git a/tests/ui/associated-inherent-types/issue-109071.rs b/tests/ui/associated-inherent-types/issue-109071.rs index 29eef081a32..97803ae7191 100644 --- a/tests/ui/associated-inherent-types/issue-109071.rs +++ b/tests/ui/associated-inherent-types/issue-109071.rs @@ -13,7 +13,7 @@ impl<T> Windows { //~ ERROR: missing generics for struct `Windows` impl<T> Windows<T> { fn T() -> Option<Self::Item> {} - //~^ ERROR: ambiguous associated type + //[no_gate]~^ ERROR: ambiguous associated type } fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-109071.with_gate.stderr b/tests/ui/associated-inherent-types/issue-109071.with_gate.stderr index a7d17e2d5eb..1324cb9bb9b 100644 --- a/tests/ui/associated-inherent-types/issue-109071.with_gate.stderr +++ b/tests/ui/associated-inherent-types/issue-109071.with_gate.stderr @@ -20,20 +20,7 @@ help: add missing generic argument LL | impl<T> Windows<T> { | +++ -error[E0223]: ambiguous associated type - --> $DIR/issue-109071.rs:15:22 - | -LL | fn T() -> Option<Self::Item> {} - | ^^^^^^^^^^ - | -help: use fully-qualified syntax - | -LL | fn T() -> Option<<Windows<T> as IntoAsyncIterator>::Item> {} - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL | fn T() -> Option<<Windows<T> as IntoIterator>::Item> {} - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0107, E0223, E0637. +Some errors have detailed explanations: E0107, E0637. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/associated-inherent-types/issue-109299.rs b/tests/ui/associated-inherent-types/issue-109299.rs index b6c010c34e4..84e4f9e7252 100644 --- a/tests/ui/associated-inherent-types/issue-109299.rs +++ b/tests/ui/associated-inherent-types/issue-109299.rs @@ -8,6 +8,5 @@ impl Lexer<'d> { //~ ERROR use of undeclared lifetime name `'d` } fn test(_: Lexer::Cursor) {} -//~^ ERROR: lifetime may not live long enough fn main() {} diff --git a/tests/ui/associated-inherent-types/issue-109299.stderr b/tests/ui/associated-inherent-types/issue-109299.stderr index f108a52b92c..1e11c0e8c2a 100644 --- a/tests/ui/associated-inherent-types/issue-109299.stderr +++ b/tests/ui/associated-inherent-types/issue-109299.stderr @@ -6,15 +6,6 @@ LL | impl Lexer<'d> { | | | help: consider introducing lifetime `'d` here: `<'d>` -error: lifetime may not live long enough - --> $DIR/issue-109299.rs:10:1 - | -LL | fn test(_: Lexer::Cursor) {} - | ^^^^^^^^-^^^^^^^^^^^^^^^^ - | | | - | | has type `Lexer<'1>::Cursor` - | requires that `'1` must outlive `'static` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0261`. diff --git a/tests/ui/async-await/coroutine-desc.stderr b/tests/ui/async-await/coroutine-desc.stderr index 1f1e303ea4c..4c165ff619a 100644 --- a/tests/ui/async-await/coroutine-desc.stderr +++ b/tests/ui/async-await/coroutine-desc.stderr @@ -10,6 +10,8 @@ LL | fun(async {}, async {}); | = note: expected `async` block `{async block@$DIR/coroutine-desc.rs:10:9: 10:17}` found `async` block `{async block@$DIR/coroutine-desc.rs:10:19: 10:27}` + = note: no two async blocks, even if identical, have the same type + = help: consider pinning your async block and casting it to a trait object note: function defined here --> $DIR/coroutine-desc.rs:8:4 | @@ -51,6 +53,8 @@ LL | fun((async || {})(), (async || {})()); | = note: expected `async` closure body `{async closure body@$DIR/coroutine-desc.rs:14:19: 14:21}` found `async` closure body `{async closure body@$DIR/coroutine-desc.rs:14:36: 14:38}` + = note: no two async blocks, even if identical, have the same type + = help: consider pinning your async block and casting it to a trait object note: function defined here --> $DIR/coroutine-desc.rs:8:4 | diff --git a/tests/ui/async-await/no-async-const.rs b/tests/ui/async-await/no-async-const.rs index c5485ebc9b6..38a5df3576b 100644 --- a/tests/ui/async-await/no-async-const.rs +++ b/tests/ui/async-await/no-async-const.rs @@ -2,5 +2,5 @@ //@ compile-flags: --crate-type lib pub async const fn x() {} -//~^ ERROR expected one of `extern`, `fn`, or `unsafe`, found keyword `const` +//~^ ERROR expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `const` //~| ERROR functions cannot be both `const` and `async` diff --git a/tests/ui/async-await/no-async-const.stderr b/tests/ui/async-await/no-async-const.stderr index 524d778c09b..d692ba8f473 100644 --- a/tests/ui/async-await/no-async-const.stderr +++ b/tests/ui/async-await/no-async-const.stderr @@ -1,10 +1,10 @@ -error: expected one of `extern`, `fn`, or `unsafe`, found keyword `const` +error: expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `const` --> $DIR/no-async-const.rs:4:11 | LL | pub async const fn x() {} | ------^^^^^ | | | - | | expected one of `extern`, `fn`, or `unsafe` + | | expected one of `extern`, `fn`, `safe`, or `unsafe` | help: `const` must come before `async`: `const async` | = note: keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern` diff --git a/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs b/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs new file mode 100644 index 00000000000..ce365d1a8b1 --- /dev/null +++ b/tests/ui/attributes/unsafe/cfg-unsafe-attributes.rs @@ -0,0 +1,7 @@ +//@ build-pass +#![feature(unsafe_attributes)] + +#[cfg_attr(all(), unsafe(no_mangle))] +fn a() {} + +fn main() {} diff --git a/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs b/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs new file mode 100644 index 00000000000..774ce86c096 --- /dev/null +++ b/tests/ui/attributes/unsafe/derive-unsafe-attributes.rs @@ -0,0 +1,6 @@ +#![feature(unsafe_attributes)] + +#[derive(unsafe(Debug))] //~ ERROR: traits in `#[derive(...)]` don't accept `unsafe(...)` +struct Foo; + +fn main() {} diff --git a/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr new file mode 100644 index 00000000000..fc0daf16790 --- /dev/null +++ b/tests/ui/attributes/unsafe/derive-unsafe-attributes.stderr @@ -0,0 +1,8 @@ +error: traits in `#[derive(...)]` don't accept `unsafe(...)` + --> $DIR/derive-unsafe-attributes.rs:3:10 + | +LL | #[derive(unsafe(Debug))] + | ^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/attributes/unsafe/double-unsafe-attributes.rs b/tests/ui/attributes/unsafe/double-unsafe-attributes.rs new file mode 100644 index 00000000000..a6c0ea578f2 --- /dev/null +++ b/tests/ui/attributes/unsafe/double-unsafe-attributes.rs @@ -0,0 +1,9 @@ +#![feature(unsafe_attributes)] + +#[unsafe(unsafe(no_mangle))] +//~^ ERROR expected identifier, found keyword `unsafe` +//~| ERROR cannot find attribute `r#unsafe` in this scope +//~| ERROR `r#unsafe` is not an unsafe attribute +fn a() {} + +fn main() {} diff --git a/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr new file mode 100644 index 00000000000..1c07a5bf8ba --- /dev/null +++ b/tests/ui/attributes/unsafe/double-unsafe-attributes.stderr @@ -0,0 +1,27 @@ +error: expected identifier, found keyword `unsafe` + --> $DIR/double-unsafe-attributes.rs:3:10 + | +LL | #[unsafe(unsafe(no_mangle))] + | ^^^^^^ expected identifier, found keyword + | +help: escape `unsafe` to use it as an identifier + | +LL | #[unsafe(r#unsafe(no_mangle))] + | ++ + +error: cannot find attribute `r#unsafe` in this scope + --> $DIR/double-unsafe-attributes.rs:3:10 + | +LL | #[unsafe(unsafe(no_mangle))] + | ^^^^^^ + +error: `r#unsafe` is not an unsafe attribute + --> $DIR/double-unsafe-attributes.rs:3:3 + | +LL | #[unsafe(unsafe(no_mangle))] + | ^^^^^^ + | + = note: extraneous unsafe is not allowed in attributes + +error: aborting due to 3 previous errors + diff --git a/tests/ui/attributes/unsafe/unsafe-attributes.rs b/tests/ui/attributes/unsafe/unsafe-attributes.rs new file mode 100644 index 00000000000..e7620a18048 --- /dev/null +++ b/tests/ui/attributes/unsafe/unsafe-attributes.rs @@ -0,0 +1,7 @@ +//@ build-pass +#![feature(unsafe_attributes)] + +#[unsafe(no_mangle)] +fn a() {} + +fn main() {} diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute.rs b/tests/ui/attributes/unsafe/unsafe-safe-attribute.rs new file mode 100644 index 00000000000..67db36afd2e --- /dev/null +++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute.rs @@ -0,0 +1,6 @@ +#![feature(unsafe_attributes)] + +#[unsafe(repr(C))] //~ ERROR: is not an unsafe attribute +struct Foo {} + +fn main() {} diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr b/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr new file mode 100644 index 00000000000..0602af34e4f --- /dev/null +++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute.stderr @@ -0,0 +1,10 @@ +error: `repr` is not an unsafe attribute + --> $DIR/unsafe-safe-attribute.rs:3:3 + | +LL | #[unsafe(repr(C))] + | ^^^^^^ + | + = note: extraneous unsafe is not allowed in attributes + +error: aborting due to 1 previous error + diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs new file mode 100644 index 00000000000..ff2eb61b405 --- /dev/null +++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.rs @@ -0,0 +1,8 @@ +#![feature(unsafe_attributes)] + +#[unsafe(diagnostic::on_unimplemented( //~ ERROR: is not an unsafe attribute + message = "testing", +))] +trait Foo {} + +fn main() {} diff --git a/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr new file mode 100644 index 00000000000..584dacf4d8c --- /dev/null +++ b/tests/ui/attributes/unsafe/unsafe-safe-attribute_diagnostic.stderr @@ -0,0 +1,10 @@ +error: `diagnostic::on_unimplemented` is not an unsafe attribute + --> $DIR/unsafe-safe-attribute_diagnostic.rs:3:3 + | +LL | #[unsafe(diagnostic::on_unimplemented( + | ^^^^^^ + | + = note: extraneous unsafe is not allowed in attributes + +error: aborting due to 1 previous error + diff --git a/tests/ui/borrowck/generic_const_early_param.rs b/tests/ui/borrowck/generic_const_early_param.rs index f601e45d21f..0d07b6869f1 100644 --- a/tests/ui/borrowck/generic_const_early_param.rs +++ b/tests/ui/borrowck/generic_const_early_param.rs @@ -5,7 +5,6 @@ struct DataWrapper<'static> { //~^ ERROR invalid lifetime parameter name: `'static` data: &'a [u8; Self::SIZE], //~^ ERROR use of undeclared lifetime name `'a` - //~^^ ERROR lifetime may not live long enough } impl DataWrapper<'a> { diff --git a/tests/ui/borrowck/generic_const_early_param.stderr b/tests/ui/borrowck/generic_const_early_param.stderr index a71ab09396e..3f56d6a3325 100644 --- a/tests/ui/borrowck/generic_const_early_param.stderr +++ b/tests/ui/borrowck/generic_const_early_param.stderr @@ -14,7 +14,7 @@ LL | data: &'a [u8; Self::SIZE], | ^^ undeclared lifetime error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/generic_const_early_param.rs:11:18 + --> $DIR/generic_const_early_param.rs:10:18 | LL | impl DataWrapper<'a> { | - ^^ undeclared lifetime @@ -30,13 +30,7 @@ LL | #![feature(generic_const_exprs)] = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information = note: `#[warn(incomplete_features)]` on by default -error: lifetime may not live long enough - --> $DIR/generic_const_early_param.rs:6:20 - | -LL | data: &'a [u8; Self::SIZE], - | ^^^^^^^^^^ requires that `'_` must outlive `'static` - -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 3 previous errors; 1 warning emitted Some errors have detailed explanations: E0261, E0262. For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/coherence/coherence-impls-copy.stderr b/tests/ui/coherence/coherence-impls-copy.stderr index 2d2c5064043..f529a056b0f 100644 --- a/tests/ui/coherence/coherence-impls-copy.stderr +++ b/tests/ui/coherence/coherence-impls-copy.stderr @@ -1,14 +1,3 @@ -error[E0117]: only traits defined in the current crate can be implemented for primitive types - --> $DIR/coherence-impls-copy.rs:5:1 - | -LL | impl Copy for i32 {} - | ^^^^^^^^^^^^^^--- - | | | - | | `i32` is not defined in the current crate - | impl doesn't use only types from inside the current crate - | - = note: define and implement a trait or new type instead - error[E0119]: conflicting implementations of trait `Copy` for type `&NotSync` --> $DIR/coherence-impls-copy.rs:28:1 | @@ -30,6 +19,17 @@ LL | impl Copy for &'static [NotSync] {} | = note: define and implement a trait or new type instead +error[E0117]: only traits defined in the current crate can be implemented for primitive types + --> $DIR/coherence-impls-copy.rs:5:1 + | +LL | impl Copy for i32 {} + | ^^^^^^^^^^^^^^--- + | | | + | | `i32` is not defined in the current crate + | impl doesn't use only types from inside the current crate + | + = note: define and implement a trait or new type instead + error[E0206]: the trait `Copy` cannot be implemented for this type --> $DIR/coherence-impls-copy.rs:21:15 | diff --git a/tests/ui/coherence/orphan-check-opaque-types-not-covering.classic.stderr b/tests/ui/coherence/orphan-check-opaque-types-not-covering.classic.stderr new file mode 100644 index 00000000000..44f76f321cf --- /dev/null +++ b/tests/ui/coherence/orphan-check-opaque-types-not-covering.classic.stderr @@ -0,0 +1,21 @@ +error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + --> $DIR/orphan-check-opaque-types-not-covering.rs:17:6 + | +LL | impl<T> foreign::Trait0<Local, T, ()> for Identity<T> {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last + +error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + --> $DIR/orphan-check-opaque-types-not-covering.rs:26:6 + | +LL | impl<T> foreign::Trait1<Local, T> for Opaque<T> {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/tests/ui/coherence/orphan-check-opaque-types-not-covering.next.stderr b/tests/ui/coherence/orphan-check-opaque-types-not-covering.next.stderr new file mode 100644 index 00000000000..44f76f321cf --- /dev/null +++ b/tests/ui/coherence/orphan-check-opaque-types-not-covering.next.stderr @@ -0,0 +1,21 @@ +error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + --> $DIR/orphan-check-opaque-types-not-covering.rs:17:6 + | +LL | impl<T> foreign::Trait0<Local, T, ()> for Identity<T> {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last + +error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + --> $DIR/orphan-check-opaque-types-not-covering.rs:26:6 + | +LL | impl<T> foreign::Trait1<Local, T> for Opaque<T> {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Local`) + | + = note: implementing a foreign trait is only possible if at least one of the types for which it is implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0210`. diff --git a/tests/ui/coherence/orphan-check-opaque-types-not-covering.rs b/tests/ui/coherence/orphan-check-opaque-types-not-covering.rs new file mode 100644 index 00000000000..8dc02b081c5 --- /dev/null +++ b/tests/ui/coherence/orphan-check-opaque-types-not-covering.rs @@ -0,0 +1,31 @@ +// Opaque types never cover type parameters. + +//@ revisions: classic next +//@[next] compile-flags: -Znext-solver + +//@ aux-crate:foreign=parametrized-trait.rs +//@ edition:2021 + +#![feature(type_alias_impl_trait)] + +type Identity<T> = impl Sized; + +fn define_identity<T>(x: T) -> Identity<T> { + x +} + +impl<T> foreign::Trait0<Local, T, ()> for Identity<T> {} +//~^ ERROR type parameter `T` must be covered by another type + +type Opaque<T> = impl Sized; + +fn define_local<T>() -> Opaque<T> { + Local +} + +impl<T> foreign::Trait1<Local, T> for Opaque<T> {} +//~^ ERROR type parameter `T` must be covered by another type + +struct Local; + +fn main() {} diff --git a/tests/ui/coherence/re-rebalance-coherence.rs b/tests/ui/coherence/re-rebalance-coherence.rs index 9c176d5b1b1..5383a634617 100644 --- a/tests/ui/coherence/re-rebalance-coherence.rs +++ b/tests/ui/coherence/re-rebalance-coherence.rs @@ -4,6 +4,7 @@ extern crate re_rebalance_coherence_lib as lib; use lib::*; +#[allow(dead_code)] struct Oracle; impl Backend for Oracle {} impl<'a, T:'a, Tab> QueryFragment<Oracle> for BatchInsert<'a, T, Tab> {} diff --git a/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs b/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs index 05bd0d91168..c55f3dcec68 100644 --- a/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs +++ b/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs @@ -1,4 +1,5 @@ //@ edition:2021 +//@ check-pass // issues rust-lang/rust#111911 // test for ICE opaque type with non-universal region substs @@ -6,8 +7,6 @@ #![allow(incomplete_features)] pub async fn foo<const X: &'static str>() {} -//~^ ERROR const parameter `X` is part of concrete type but not used in parameter list for the `impl Trait` type alias -//~| ERROR const parameter `X` is part of concrete type but not used in parameter list for the `impl Trait` type alias fn bar<const N: &'static u8>() -> impl Sized {} pub fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.stderr b/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.stderr deleted file mode 100644 index 1bdb9cd9501..00000000000 --- a/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: const parameter `X` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/opaque_type_with_non-universal_region_substs_ice-111911.rs:8:43 - | -LL | pub async fn foo<const X: &'static str>() {} - | ^^ - -error: const parameter `X` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/opaque_type_with_non-universal_region_substs_ice-111911.rs:8:43 - | -LL | pub async fn foo<const X: &'static str>() {} - | ^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors - diff --git a/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.rs b/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.rs index 68b8b489816..569e57fa326 100644 --- a/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.rs +++ b/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.rs @@ -24,7 +24,6 @@ fn via_associated_const() { trait Trait { const FALSE: bool = assert::is_transmutable::<Src, Dst, Context, {}>(); //~^ ERROR mismatched types - //~| ERROR `Src` cannot be safely transmuted into `Dst` //~| ERROR mismatched types } } diff --git a/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr b/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr index 1dbacaee3c2..a8fc742e89f 100644 --- a/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr +++ b/tests/ui/const-generics/adt_const_params/transmutable-ice-110969.stderr @@ -12,28 +12,13 @@ error[E0308]: mismatched types LL | const FALSE: bool = assert::is_transmutable::<Src, Dst, Context, {}>(); | ^^ expected `Assume`, found `()` -error[E0277]: `Src` cannot be safely transmuted into `Dst` - --> $DIR/transmutable-ice-110969.rs:25:60 - | -LL | const FALSE: bool = assert::is_transmutable::<Src, Dst, Context, {}>(); - | ^^^ `Dst` may carry safety invariants - | -note: required by a bound in `is_transmutable` - --> $DIR/transmutable-ice-110969.rs:11:14 - | -LL | pub fn is_transmutable<Src, Dst, Context, const ASSUME: std::mem::Assume>() - | --------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom<Src, Context, ASSUME>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` - error[E0308]: mismatched types --> $DIR/transmutable-ice-110969.rs:25:29 | LL | const FALSE: bool = assert::is_transmutable::<Src, Dst, Context, {}>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0107, E0277, E0308. +Some errors have detailed explanations: E0107, E0308. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/const-generics/const-param-type-depends-on-type-param.full.stderr b/tests/ui/const-generics/const-param-type-depends-on-type-param.full.stderr index 2bfa604fc56..49cf4281323 100644 --- a/tests/ui/const-generics/const-param-type-depends-on-type-param.full.stderr +++ b/tests/ui/const-generics/const-param-type-depends-on-type-param.full.stderr @@ -6,6 +6,16 @@ LL | pub struct Dependent<T, const X: T>([(); X]); | = note: type parameters may not be used in the type of const parameters -error: aborting due to 1 previous error +error[E0392]: type parameter `T` is never used + --> $DIR/const-param-type-depends-on-type-param.rs:11:22 + | +LL | pub struct Dependent<T, const X: T>([(); X]); + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0770`. +Some errors have detailed explanations: E0392, E0770. +For more information about an error, try `rustc --explain E0392`. diff --git a/tests/ui/const-generics/const-param-type-depends-on-type-param.min.stderr b/tests/ui/const-generics/const-param-type-depends-on-type-param.min.stderr index 2bfa604fc56..49cf4281323 100644 --- a/tests/ui/const-generics/const-param-type-depends-on-type-param.min.stderr +++ b/tests/ui/const-generics/const-param-type-depends-on-type-param.min.stderr @@ -6,6 +6,16 @@ LL | pub struct Dependent<T, const X: T>([(); X]); | = note: type parameters may not be used in the type of const parameters -error: aborting due to 1 previous error +error[E0392]: type parameter `T` is never used + --> $DIR/const-param-type-depends-on-type-param.rs:11:22 + | +LL | pub struct Dependent<T, const X: T>([(); X]); + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0770`. +Some errors have detailed explanations: E0392, E0770. +For more information about an error, try `rustc --explain E0392`. diff --git a/tests/ui/const-generics/const-param-type-depends-on-type-param.rs b/tests/ui/const-generics/const-param-type-depends-on-type-param.rs index 1583fc4ee6c..5503b08930b 100644 --- a/tests/ui/const-generics/const-param-type-depends-on-type-param.rs +++ b/tests/ui/const-generics/const-param-type-depends-on-type-param.rs @@ -10,5 +10,6 @@ pub struct Dependent<T, const X: T>([(); X]); //~^ ERROR: the type of const parameters must not depend on other generic parameters +//~| ERROR: type parameter `T` is never used fn main() {} diff --git a/tests/ui/const-generics/defaults/repr-c-issue-82792.rs b/tests/ui/const-generics/defaults/repr-c-issue-82792.rs index c23187598bc..4bf2fa761ea 100644 --- a/tests/ui/const-generics/defaults/repr-c-issue-82792.rs +++ b/tests/ui/const-generics/defaults/repr-c-issue-82792.rs @@ -2,6 +2,7 @@ //@ run-pass +#[allow(dead_code)] #[repr(C)] pub struct Loaf<T: Sized, const N: usize = 1> { head: [T; N], diff --git a/tests/ui/const-generics/generic_const_exprs/associated-consts.rs b/tests/ui/const-generics/generic_const_exprs/associated-consts.rs index 5d2198f50ad..50a6102c605 100644 --- a/tests/ui/const-generics/generic_const_exprs/associated-consts.rs +++ b/tests/ui/const-generics/generic_const_exprs/associated-consts.rs @@ -16,7 +16,8 @@ impl BlockCipher for BarCipher { const BLOCK_SIZE: usize = 32; } -pub struct Block<C>(#[allow(dead_code)] C); +#[allow(dead_code)] +pub struct Block<C>(C); pub fn test<C: BlockCipher, const M: usize>() where diff --git a/tests/ui/const-generics/generic_const_exprs/error_in_ty.rs b/tests/ui/const-generics/generic_const_exprs/error_in_ty.rs new file mode 100644 index 00000000000..29ad935c014 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/error_in_ty.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Znext-solver=coherence + +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +pub struct A<const z: [usize; x]> {} +//~^ ERROR: cannot find value `x` in this scope +//~| ERROR: `[usize; x]` is forbidden as the type of a const generic parameter + +impl A<2> { + //~^ ERROR: mismatched types + pub const fn B() {} + //~^ ERROR: duplicate definitions +} + +impl A<2> { + //~^ ERROR: mismatched types + pub const fn B() {} +} + +fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr b/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr new file mode 100644 index 00000000000..0e40255bcf5 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/error_in_ty.stderr @@ -0,0 +1,45 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/error_in_ty.rs:6:31 + | +LL | pub struct A<const z: [usize; x]> {} + | - ^ help: a const parameter with a similar name exists: `z` + | | + | similarly named const parameter `z` defined here + +error: `[usize; x]` is forbidden as the type of a const generic parameter + --> $DIR/error_in_ty.rs:6:23 + | +LL | pub struct A<const z: [usize; x]> {} + | ^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` +help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types + | +LL + #![feature(adt_const_params)] + | + +error[E0308]: mismatched types + --> $DIR/error_in_ty.rs:10:8 + | +LL | impl A<2> { + | ^ expected `[usize; x]`, found integer + +error[E0308]: mismatched types + --> $DIR/error_in_ty.rs:16:8 + | +LL | impl A<2> { + | ^ expected `[usize; x]`, found integer + +error[E0592]: duplicate definitions with name `B` + --> $DIR/error_in_ty.rs:12:5 + | +LL | pub const fn B() {} + | ^^^^^^^^^^^^^^^^ duplicate definitions for `B` +... +LL | pub const fn B() {} + | ---------------- other definition for `B` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0308, E0425, E0592. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/generic_const_exprs/eval-privacy.rs b/tests/ui/const-generics/generic_const_exprs/eval-privacy.rs index 8023b998a40..b662939c27e 100644 --- a/tests/ui/const-generics/generic_const_exprs/eval-privacy.rs +++ b/tests/ui/const-generics/generic_const_exprs/eval-privacy.rs @@ -9,12 +9,14 @@ pub trait Trait { fn assoc_fn() -> Self::AssocTy; } -impl<const U: u8> Trait for Const<U> // OK, trait impl predicates +impl<const U: u8> Trait for Const<U> where - Const<{ my_const_fn(U) }>: , + // OK, trait impl predicates + Const<{ my_const_fn(U) }>:, { type AssocTy = Const<{ my_const_fn(U) }>; //~^ ERROR private type + //~| ERROR private type fn assoc_fn() -> Self::AssocTy { Const } diff --git a/tests/ui/const-generics/generic_const_exprs/eval-privacy.stderr b/tests/ui/const-generics/generic_const_exprs/eval-privacy.stderr index 043fa34d605..98dac313be4 100644 --- a/tests/ui/const-generics/generic_const_exprs/eval-privacy.stderr +++ b/tests/ui/const-generics/generic_const_exprs/eval-privacy.stderr @@ -1,5 +1,5 @@ error[E0446]: private type `fn(u8) -> u8 {my_const_fn}` in public interface - --> $DIR/eval-privacy.rs:16:5 + --> $DIR/eval-privacy.rs:17:5 | LL | type AssocTy = Const<{ my_const_fn(U) }>; | ^^^^^^^^^^^^ can't leak private type @@ -7,6 +7,17 @@ LL | type AssocTy = Const<{ my_const_fn(U) }>; LL | const fn my_const_fn(val: u8) -> u8 { | ----------------------------------- `fn(u8) -> u8 {my_const_fn}` declared as private -error: aborting due to 1 previous error +error[E0446]: private type `fn(u8) -> u8 {my_const_fn}` in public interface + --> $DIR/eval-privacy.rs:17:5 + | +LL | type AssocTy = Const<{ my_const_fn(U) }>; + | ^^^^^^^^^^^^ can't leak private type +... +LL | const fn my_const_fn(val: u8) -> u8 { + | ----------------------------------- `fn(u8) -> u8 {my_const_fn}` declared as private + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0446`. diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.rs b/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.rs index 42c1cc507b5..b3bbb842638 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.rs +++ b/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.rs @@ -1,14 +1,11 @@ #![feature(generic_const_exprs)] #![allow(incomplete_features)] -#![deny(where_clauses_object_safety)] const fn bar<T: ?Sized>() -> usize { 7 } trait Foo { fn test(&self) where [u8; bar::<Self>()]: Sized; - //~^ ERROR the trait `Foo` cannot be made into an object - //~| WARN this was previously accepted by the compiler but is being phased out } impl Foo for () { @@ -16,7 +13,9 @@ impl Foo for () { } fn use_dyn(v: &dyn Foo) { + //~^ ERROR the trait `Foo` cannot be made into an object v.test(); + //~^ ERROR the trait `Foo` cannot be made into an object } fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.stderr b/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.stderr index 9e480ce9b85..fde5d3ce772 100644 --- a/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.stderr +++ b/tests/ui/const-generics/generic_const_exprs/object-safety-err-where-bounds.stderr @@ -1,24 +1,35 @@ -error: the trait `Foo` cannot be made into an object - --> $DIR/object-safety-err-where-bounds.rs:9:8 +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/object-safety-err-where-bounds.rs:15:16 | -LL | fn test(&self) where [u8; bar::<Self>()]: Sized; - | ^^^^ +LL | fn use_dyn(v: &dyn Foo) { + | ^^^^^^^ `Foo` cannot be made into an object | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #51443 <https://github.com/rust-lang/rust/issues/51443> 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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/object-safety-err-where-bounds.rs:9:8 + --> $DIR/object-safety-err-where-bounds.rs:8:8 | LL | trait Foo { | --- this trait cannot be made into an object... LL | fn test(&self) where [u8; bar::<Self>()]: Sized; | ^^^^ ...because method `test` references the `Self` type in its `where` clause = help: consider moving `test` to another trait -note: the lint level is defined here - --> $DIR/object-safety-err-where-bounds.rs:3:9 + = help: only type `()` implements the trait, consider using it directly instead + +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/object-safety-err-where-bounds.rs:17:5 + | +LL | v.test(); + | ^^^^^^^^ `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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/object-safety-err-where-bounds.rs:8:8 | -LL | #![deny(where_clauses_object_safety)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait Foo { + | --- this trait cannot be made into an object... +LL | fn test(&self) where [u8; bar::<Self>()]: Sized; + | ^^^^ ...because method `test` references the `Self` type in its `where` clause + = help: consider moving `test` to another trait + = help: only type `()` implements the trait, consider using it directly instead -error: aborting due to 1 previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/const-generics/issues/issue-71381.full.stderr b/tests/ui/const-generics/issues/issue-71381.full.stderr index 5d780074696..05e847cf4c8 100644 --- a/tests/ui/const-generics/issues/issue-71381.full.stderr +++ b/tests/ui/const-generics/issues/issue-71381.full.stderr @@ -7,13 +7,25 @@ LL | pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern " = note: type parameters may not be used in the type of const parameters error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/issue-71381.rs:22:40 + --> $DIR/issue-71381.rs:24:40 | LL | const FN: unsafe extern "C" fn(Args), | ^^^^ the type must not depend on the parameter `Args` | = note: type parameters may not be used in the type of const parameters -error: aborting due to 2 previous errors +error[E0594]: cannot assign to `self.0`, which is behind a `&` reference + --> $DIR/issue-71381.rs:17:9 + | +LL | self.0 = Self::trampiline::<Args, IDX, FN> as _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written + | +help: consider changing this to be a mutable reference + | +LL | pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&mut self) { + | ~~~~~~~~~ + +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0770`. +Some errors have detailed explanations: E0594, E0770. +For more information about an error, try `rustc --explain E0594`. diff --git a/tests/ui/const-generics/issues/issue-71381.min.stderr b/tests/ui/const-generics/issues/issue-71381.min.stderr index 5d780074696..1c30e885d1b 100644 --- a/tests/ui/const-generics/issues/issue-71381.min.stderr +++ b/tests/ui/const-generics/issues/issue-71381.min.stderr @@ -7,13 +7,41 @@ LL | pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern " = note: type parameters may not be used in the type of const parameters error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/issue-71381.rs:22:40 + --> $DIR/issue-71381.rs:24:40 | LL | const FN: unsafe extern "C" fn(Args), | ^^^^ the type must not depend on the parameter `Args` | = note: type parameters may not be used in the type of const parameters -error: aborting due to 2 previous errors +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71381.rs:14:61 + | +LL | pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71381.rs:24:19 + | +LL | const FN: unsafe extern "C" fn(Args), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + +error[E0594]: cannot assign to `self.0`, which is behind a `&` reference + --> $DIR/issue-71381.rs:17:9 + | +LL | self.0 = Self::trampiline::<Args, IDX, FN> as _ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written + | +help: consider changing this to be a mutable reference + | +LL | pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&mut self) { + | ~~~~~~~~~ + +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0770`. +Some errors have detailed explanations: E0594, E0770. +For more information about an error, try `rustc --explain E0594`. diff --git a/tests/ui/const-generics/issues/issue-71381.rs b/tests/ui/const-generics/issues/issue-71381.rs index 7f2e14944e2..166b724a7a3 100644 --- a/tests/ui/const-generics/issues/issue-71381.rs +++ b/tests/ui/const-generics/issues/issue-71381.rs @@ -13,7 +13,9 @@ unsafe extern "C" fn pass(args: PassArg) { impl Test { pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) { //~^ ERROR: the type of const parameters must not depend on other generic parameters + //[min]~^^ ERROR: using function pointers as const generic parameters is forbidden self.0 = Self::trampiline::<Args, IDX, FN> as _ + //~^ ERROR: cannot assign to `self.0` } unsafe extern "C" fn trampiline< @@ -21,6 +23,7 @@ impl Test { const IDX: usize, const FN: unsafe extern "C" fn(Args), //~^ ERROR: the type of const parameters must not depend on other generic parameters + //[min]~^^ ERROR: using function pointers as const generic parameters is forbidden >( args: Args, ) { diff --git a/tests/ui/const-generics/issues/issue-71611.min.stderr b/tests/ui/const-generics/issues/issue-71611.min.stderr index 6f6a9fc21a6..b01936f4d25 100644 --- a/tests/ui/const-generics/issues/issue-71611.min.stderr +++ b/tests/ui/const-generics/issues/issue-71611.min.stderr @@ -6,6 +6,14 @@ LL | fn func<A, const F: fn(inner: A)>(outer: A) { | = note: type parameters may not be used in the type of const parameters -error: aborting due to 1 previous error +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71611.rs:5:21 + | +LL | fn func<A, const F: fn(inner: A)>(outer: A) { + | ^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0770`. diff --git a/tests/ui/const-generics/issues/issue-71611.rs b/tests/ui/const-generics/issues/issue-71611.rs index 0e0c08146b2..c6c1e267171 100644 --- a/tests/ui/const-generics/issues/issue-71611.rs +++ b/tests/ui/const-generics/issues/issue-71611.rs @@ -4,6 +4,7 @@ fn func<A, const F: fn(inner: A)>(outer: A) { //~^ ERROR: the type of const parameters must not depend on other generic parameters + //[min]~| ERROR: using function pointers as const generic parameters is forbidden F(outer); } diff --git a/tests/ui/const-generics/not_wf_param_in_rpitit.rs b/tests/ui/const-generics/not_wf_param_in_rpitit.rs new file mode 100644 index 00000000000..5471dc9022f --- /dev/null +++ b/tests/ui/const-generics/not_wf_param_in_rpitit.rs @@ -0,0 +1,14 @@ +//@ edition:2021 + +trait Trait<const N: Trait = bar> { + //~^ ERROR: cannot find value `bar` in this scope + //~| ERROR: cycle detected when computing type of `Trait::N` + //~| ERROR: the trait `Trait` cannot be made into an object + //~| ERROR: the trait `Trait` cannot be made into an object + //~| ERROR: the trait `Trait` cannot be made into an object + //~| ERROR: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter + //~| ERROR: trait objects must include the `dyn` keyword + async fn a() {} +} + +fn main() {} diff --git a/tests/ui/const-generics/not_wf_param_in_rpitit.stderr b/tests/ui/const-generics/not_wf_param_in_rpitit.stderr new file mode 100644 index 00000000000..9095948d22b --- /dev/null +++ b/tests/ui/const-generics/not_wf_param_in_rpitit.stderr @@ -0,0 +1,113 @@ +error[E0425]: cannot find value `bar` in this scope + --> $DIR/not_wf_param_in_rpitit.rs:3:30 + | +LL | trait Trait<const N: Trait = bar> { + | ^^^ not found in this scope + +error[E0391]: cycle detected when computing type of `Trait::N` + --> $DIR/not_wf_param_in_rpitit.rs:3:22 + | +LL | trait Trait<const N: Trait = bar> { + | ^^^^^ + | + = note: ...which immediately requires computing type of `Trait::N` again +note: cycle used when computing explicit predicates of trait `Trait` + --> $DIR/not_wf_param_in_rpitit.rs:3:1 + | +LL | trait Trait<const N: Trait = bar> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = 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[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/not_wf_param_in_rpitit.rs:3:22 + | +LL | trait Trait<const N: Trait = bar> { + | ^^^^^ `Trait` 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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/not_wf_param_in_rpitit.rs:11:14 + | +LL | trait Trait<const N: Trait = bar> { + | ----- this trait cannot be made into an object... +... +LL | async fn a() {} + | ^ ...because associated function `a` has no `self` parameter +help: consider turning `a` into a method by giving it a `&self` argument + | +LL | async fn a(&self) {} + | +++++ +help: alternatively, consider constraining `a` so it does not apply to trait objects + | +LL | async fn a() where Self: Sized {} + | +++++++++++++++++ + +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/not_wf_param_in_rpitit.rs:3:13 + | +LL | trait Trait<const N: Trait = bar> { + | ^^^^^^^^^^^^^^^^^^^^ `Trait` 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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/not_wf_param_in_rpitit.rs:11:14 + | +LL | trait Trait<const N: Trait = bar> { + | ----- this trait cannot be made into an object... +... +LL | async fn a() {} + | ^ ...because associated function `a` has no `self` parameter +help: consider turning `a` into a method by giving it a `&self` argument + | +LL | async fn a(&self) {} + | +++++ +help: alternatively, consider constraining `a` so it does not apply to trait objects + | +LL | async fn a() where Self: Sized {} + | +++++++++++++++++ + +error: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter + --> $DIR/not_wf_param_in_rpitit.rs:3:22 + | +LL | trait Trait<const N: Trait = bar> { + | ^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + +error[E0038]: the trait `Trait` cannot be made into an object + --> $DIR/not_wf_param_in_rpitit.rs:3:13 + | +LL | trait Trait<const N: Trait = bar> { + | ^^^^^^^^^^^^^^^^^^^^ `Trait` 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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/not_wf_param_in_rpitit.rs:11:14 + | +LL | trait Trait<const N: Trait = bar> { + | ----- this trait cannot be made into an object... +... +LL | async fn a() {} + | ^ ...because associated function `a` has no `self` parameter + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider turning `a` into a method by giving it a `&self` argument + | +LL | async fn a(&self) {} + | +++++ +help: alternatively, consider constraining `a` so it does not apply to trait objects + | +LL | async fn a() where Self: Sized {} + | +++++++++++++++++ + +error[E0782]: trait objects must include the `dyn` keyword + --> $DIR/not_wf_param_in_rpitit.rs:3:22 + | +LL | trait Trait<const N: Trait = bar> { + | ^^^^^ + | +help: add `dyn` keyword before this trait + | +LL | trait Trait<const N: dyn Trait = bar> { + | +++ + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0038, E0391, E0425, E0782. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/const-generics/transmute-fail.stderr b/tests/ui/const-generics/transmute-fail.stderr index 1b0d1ea50d0..b76ec10bd3f 100644 --- a/tests/ui/const-generics/transmute-fail.stderr +++ b/tests/ui/const-generics/transmute-fail.stderr @@ -13,7 +13,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- LL | std::mem::transmute(v) | ^^^^^^^^^^^^^^^^^^^ | - = note: source type: `[[u32; H]; W]` (this type does not have a fixed size) + = note: source type: `[[u32; H]; W]` (size can vary because of [u32; H]) = note: target type: `[[u32; W]; H]` (size can vary because of [u32; W]) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types diff --git a/tests/ui/const-generics/transparent-maybeunit-array-wrapper.rs b/tests/ui/const-generics/transparent-maybeunit-array-wrapper.rs index 419d605d0c8..35c41ae4615 100644 --- a/tests/ui/const-generics/transparent-maybeunit-array-wrapper.rs +++ b/tests/ui/const-generics/transparent-maybeunit-array-wrapper.rs @@ -6,6 +6,7 @@ use std::mem::MaybeUninit; +#[allow(dead_code)] #[repr(transparent)] pub struct MaybeUninitWrapper<const N: usize>(MaybeUninit<[u64; N]>); diff --git a/tests/ui/const-generics/type_not_in_scope.rs b/tests/ui/const-generics/type_not_in_scope.rs index 917abaed15e..1eb265d74d1 100644 --- a/tests/ui/const-generics/type_not_in_scope.rs +++ b/tests/ui/const-generics/type_not_in_scope.rs @@ -5,6 +5,7 @@ impl X { } } fn getn<const N: cfg_attr>() -> [u8; N] {} -//~^ ERROR expected type, found built-in attribute `cfg_attr` +//~^ ERROR: expected type, found built-in attribute `cfg_attr` +//~| ERROR: mismatched types fn main() {} diff --git a/tests/ui/const-generics/type_not_in_scope.stderr b/tests/ui/const-generics/type_not_in_scope.stderr index 5eb81ca0522..5f45550a627 100644 --- a/tests/ui/const-generics/type_not_in_scope.stderr +++ b/tests/ui/const-generics/type_not_in_scope.stderr @@ -10,7 +10,15 @@ error[E0573]: expected type, found built-in attribute `cfg_attr` LL | fn getn<const N: cfg_attr>() -> [u8; N] {} | ^^^^^^^^ not a type -error: aborting due to 2 previous errors +error[E0308]: mismatched types + --> $DIR/type_not_in_scope.rs:7:33 + | +LL | fn getn<const N: cfg_attr>() -> [u8; N] {} + | ---- ^^^^^^^ expected `[u8; N]`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0412, E0573. -For more information about an error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0308, E0412, E0573. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.rs b/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.rs index a41a159c1fd..09f7e2ba5b1 100644 --- a/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.rs +++ b/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.rs @@ -13,6 +13,7 @@ impl Opcode2 { pub fn example2(msg_type: Opcode2) -> impl FnMut(&[u8]) { move |i| match msg_type { Opcode2::OP2 => unimplemented!(), + //~^ ERROR: could not evaluate constant pattern } } diff --git a/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr b/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr index d95a8861230..9442eac0cf5 100644 --- a/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr +++ b/tests/ui/const_prop/ice-type-mismatch-when-copying-112824.stderr @@ -17,7 +17,13 @@ help: you might be missing a type parameter LL | pub struct Opcode2<S>(&'a S); | +++ -error: aborting due to 2 previous errors +error: could not evaluate constant pattern + --> $DIR/ice-type-mismatch-when-copying-112824.rs:15:9 + | +LL | Opcode2::OP2 => unimplemented!(), + | ^^^^^^^^^^^^ + +error: aborting due to 3 previous errors Some errors have detailed explanations: E0261, E0412. For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/consts/issue-103790.rs b/tests/ui/consts/issue-103790.rs index 5d130821dc8..d19115ede74 100644 --- a/tests/ui/consts/issue-103790.rs +++ b/tests/ui/consts/issue-103790.rs @@ -5,7 +5,7 @@ struct S<const S: (), const S: S = { S }>; //~^ ERROR the name `S` is already used for a generic parameter in this item's generic parameters //~| ERROR missing generics for struct `S` //~| ERROR cycle detected when computing type of `S::S` -//~| ERROR cycle detected when computing type of `S` //~| ERROR `()` is forbidden as the type of a const generic parameter +//~| ERROR `S<{const error}, {const error}>` is forbidden as the type of a const generic parameter fn main() {} diff --git a/tests/ui/consts/issue-103790.stderr b/tests/ui/consts/issue-103790.stderr index eecaf5ff63a..c671f078cb5 100644 --- a/tests/ui/consts/issue-103790.stderr +++ b/tests/ui/consts/issue-103790.stderr @@ -29,37 +29,30 @@ LL | struct S<const S: (), const S: S = { S }>; | ^ | = note: ...which immediately requires computing type of `S::S` again -note: cycle used when computing type of `S` +note: cycle used when computing explicit predicates of `S` --> $DIR/issue-103790.rs:4:1 | LL | struct S<const S: (), const S: S = { S }>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = 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 `S` - --> $DIR/issue-103790.rs:4:1 +error: `()` is forbidden as the type of a const generic parameter + --> $DIR/issue-103790.rs:4:19 | LL | struct S<const S: (), const S: S = { S }>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^ | -note: ...which requires computing type of `S::S`... - --> $DIR/issue-103790.rs:4:32 + = note: the only supported types are integers, `bool` and `char` +help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | -LL | struct S<const S: (), const S: S = { S }>; - | ^ - = note: ...which again requires computing type of `S`, completing the cycle -note: cycle used when checking that `S` is well-formed - --> $DIR/issue-103790.rs:4:1 +LL + #![feature(adt_const_params)] | -LL | struct S<const S: (), const S: S = { S }>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = 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: `()` is forbidden as the type of a const generic parameter - --> $DIR/issue-103790.rs:4:19 +error: `S<{const error}, {const error}>` is forbidden as the type of a const generic parameter + --> $DIR/issue-103790.rs:4:32 | LL | struct S<const S: (), const S: S = { S }>; - | ^^ + | ^ | = note: the only supported types are integers, `bool` and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types diff --git a/tests/ui/coroutine/async_gen_fn.none.stderr b/tests/ui/coroutine/async_gen_fn.none.stderr index 7950251a75d..047f4d82486 100644 --- a/tests/ui/coroutine/async_gen_fn.none.stderr +++ b/tests/ui/coroutine/async_gen_fn.none.stderr @@ -7,11 +7,11 @@ LL | async gen fn foo() {} = help: pass `--edition 2021` to `rustc` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error: expected one of `extern`, `fn`, or `unsafe`, found `gen` +error: expected one of `extern`, `fn`, `safe`, or `unsafe`, found `gen` --> $DIR/async_gen_fn.rs:4:7 | LL | async gen fn foo() {} - | ^^^ expected one of `extern`, `fn`, or `unsafe` + | ^^^ expected one of `extern`, `fn`, `safe`, or `unsafe` error: aborting due to 2 previous errors diff --git a/tests/ui/coroutine/async_gen_fn.rs b/tests/ui/coroutine/async_gen_fn.rs index 9e96ecf3ea6..e8be0434b9e 100644 --- a/tests/ui/coroutine/async_gen_fn.rs +++ b/tests/ui/coroutine/async_gen_fn.rs @@ -3,7 +3,7 @@ async gen fn foo() {} //[none]~^ ERROR: `async fn` is not permitted in Rust 2015 -//[none]~| ERROR: expected one of `extern`, `fn`, or `unsafe`, found `gen` +//[none]~| ERROR: expected one of `extern`, `fn`, `safe`, or `unsafe`, found `gen` //[e2024]~^^^ ERROR: gen blocks are experimental fn main() {} diff --git a/tests/ui/coroutine/gen_fn.none.stderr b/tests/ui/coroutine/gen_fn.none.stderr index c5342ee22e6..590210641ae 100644 --- a/tests/ui/coroutine/gen_fn.none.stderr +++ b/tests/ui/coroutine/gen_fn.none.stderr @@ -1,8 +1,8 @@ -error: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found `gen` +error: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `safe`, `unsafe`, or `use`, found `gen` --> $DIR/gen_fn.rs:4:1 | LL | gen fn foo() {} - | ^^^ expected one of 9 possible tokens + | ^^^ expected one of 10 possible tokens error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/gen_fn.rs b/tests/ui/coroutine/gen_fn.rs index 3228650f415..d47b7e576d0 100644 --- a/tests/ui/coroutine/gen_fn.rs +++ b/tests/ui/coroutine/gen_fn.rs @@ -2,7 +2,7 @@ //@[e2024] compile-flags: --edition 2024 -Zunstable-options gen fn foo() {} -//[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `unsafe`, or `use`, found `gen` +//[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `safe`, `unsafe`, or `use`, found `gen` //[e2024]~^^ ERROR: gen blocks are experimental fn main() {} diff --git a/tests/ui/cross-crate/auxiliary/static_init_aux.rs b/tests/ui/cross-crate/auxiliary/static_init_aux.rs index dca708733b9..832cee8d4d4 100644 --- a/tests/ui/cross-crate/auxiliary/static_init_aux.rs +++ b/tests/ui/cross-crate/auxiliary/static_init_aux.rs @@ -3,6 +3,12 @@ pub static F: fn() = f; pub static G: fn() = G0; pub static H: &(dyn Fn() + Sync) = &h; pub static I: fn() = Helper(j).mk(); +pub static K: fn() -> fn() = { + #[inline(never)] + fn k() {} + #[inline(always)] + || -> fn() { k } +}; static X: u32 = 42; static G0: fn() = g; diff --git a/tests/ui/cross-crate/static-init.rs b/tests/ui/cross-crate/static-init.rs index c4697a1d010..f8003856c5c 100644 --- a/tests/ui/cross-crate/static-init.rs +++ b/tests/ui/cross-crate/static-init.rs @@ -8,6 +8,7 @@ static F: fn() = aux::F; static G: fn() = aux::G; static H: &(dyn Fn() + Sync) = aux::H; static I: fn() = aux::I; +static K: fn() -> fn() = aux::K; fn v() -> *const u32 { V @@ -19,4 +20,5 @@ fn main() { G(); H(); I(); + K()(); } diff --git a/tests/ui/debuginfo/debuginfo-emit-llvm-ir-and-split-debuginfo.rs b/tests/ui/debuginfo/debuginfo-emit-llvm-ir-and-split-debuginfo.rs index 86117965016..3322660d1a8 100644 --- a/tests/ui/debuginfo/debuginfo-emit-llvm-ir-and-split-debuginfo.rs +++ b/tests/ui/debuginfo/debuginfo-emit-llvm-ir-and-split-debuginfo.rs @@ -1,5 +1,6 @@ //@ build-pass //@ only-linux +//@ ignore-riscv64 On this platform `-Csplit-debuginfo=unpacked` is unstable, see #120518 // //@ compile-flags: -g --emit=llvm-ir -Csplit-debuginfo=unpacked // diff --git a/tests/ui/delegation/ice-issue-124342.rs b/tests/ui/delegation/ice-issue-124342.rs new file mode 100644 index 00000000000..ad62f6bd54a --- /dev/null +++ b/tests/ui/delegation/ice-issue-124342.rs @@ -0,0 +1,12 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +mod to_reuse {} + +trait Trait { + reuse to_reuse::foo { foo } + //~^ ERROR cannot find function `foo` in module `to_reuse` + //~| ERROR cannot find value `foo` in this scope +} + +fn main() {} diff --git a/tests/ui/delegation/ice-issue-124342.stderr b/tests/ui/delegation/ice-issue-124342.stderr new file mode 100644 index 00000000000..f9a3684d649 --- /dev/null +++ b/tests/ui/delegation/ice-issue-124342.stderr @@ -0,0 +1,20 @@ +error[E0425]: cannot find function `foo` in module `to_reuse` + --> $DIR/ice-issue-124342.rs:7:21 + | +LL | reuse to_reuse::foo { foo } + | ^^^ not found in `to_reuse` + +error[E0425]: cannot find value `foo` in this scope + --> $DIR/ice-issue-124342.rs:7:27 + | +LL | reuse to_reuse::foo { foo } + | ^^^ + | +help: you might have meant to refer to the associated function + | +LL | reuse to_reuse::foo { Self::foo } + | ++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/delegation/ice-issue-124347.rs b/tests/ui/delegation/ice-issue-124347.rs new file mode 100644 index 00000000000..82a96055099 --- /dev/null +++ b/tests/ui/delegation/ice-issue-124347.rs @@ -0,0 +1,12 @@ +#![feature(fn_delegation)] +#![allow(incomplete_features)] + +trait Trait { + reuse Trait::foo { &self.0 } + //~^ ERROR recursive delegation is not supported yet +} + +reuse foo; +//~^ ERROR recursive delegation is not supported yet + +fn main() {} diff --git a/tests/ui/delegation/ice-issue-124347.stderr b/tests/ui/delegation/ice-issue-124347.stderr new file mode 100644 index 00000000000..5a3f4525d29 --- /dev/null +++ b/tests/ui/delegation/ice-issue-124347.stderr @@ -0,0 +1,14 @@ +error: recursive delegation is not supported yet + --> $DIR/ice-issue-124347.rs:5:18 + | +LL | reuse Trait::foo { &self.0 } + | ^^^ callee defined here + +error: recursive delegation is not supported yet + --> $DIR/ice-issue-124347.rs:9:7 + | +LL | reuse foo; + | ^^^ callee defined here + +error: aborting due to 2 previous errors + diff --git a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs index 6ab1fb7b039..885dacc727a 100644 --- a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs +++ b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.rs @@ -1,9 +1,9 @@ #![forbid(dead_code)] #[derive(Debug)] -pub struct Whatever { +pub struct Whatever { //~ ERROR struct `Whatever` is never constructed pub field0: (), - field1: (), //~ ERROR fields `field1`, `field2`, `field3`, and `field4` are never read + field1: (), field2: (), field3: (), field4: (), diff --git a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr index e9b757b6bae..e10d28ad03a 100644 --- a/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr +++ b/tests/ui/derives/clone-debug-dead-code-in-the-same-struct.stderr @@ -1,19 +1,9 @@ -error: fields `field1`, `field2`, `field3`, and `field4` are never read - --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:6:5 +error: struct `Whatever` is never constructed + --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:4:12 | LL | pub struct Whatever { - | -------- fields in this struct -LL | pub field0: (), -LL | field1: (), - | ^^^^^^ -LL | field2: (), - | ^^^^^^ -LL | field3: (), - | ^^^^^^ -LL | field4: (), - | ^^^^^^ + | ^^^^^^^^ | - = note: `Whatever` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis note: the lint level is defined here --> $DIR/clone-debug-dead-code-in-the-same-struct.rs:1:11 | diff --git a/tests/ui/derives/derive-hrtb-for-bare-fn-field-with-lifetime.rs b/tests/ui/derives/derive-hrtb-for-bare-fn-field-with-lifetime.rs new file mode 100644 index 00000000000..b8a42be6832 --- /dev/null +++ b/tests/ui/derives/derive-hrtb-for-bare-fn-field-with-lifetime.rs @@ -0,0 +1,13 @@ +//@ run-pass +// Issue #122622: `#[derive(Clone)]` should work for HRTB function type taking an associated type +#![allow(dead_code)] +trait SomeTrait { + type SomeType<'a>; +} + +#[derive(Clone)] +struct Foo<T: SomeTrait> { + x: for<'a> fn(T::SomeType<'a>) +} + +fn main() {} diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.current.stderr new file mode 100644 index 00000000000..bcede8a255f --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.current.stderr @@ -0,0 +1,15 @@ +error[E0277]: Very important message! + --> $DIR/type_mismatch.rs:25:14 + | +LL | verify::<u8>(); + | ^^ the trait `TheImportantOne` is not implemented for `u8` + | +note: required by a bound in `verify` + --> $DIR/type_mismatch.rs:22:14 + | +LL | fn verify<T: TheImportantOne>() {} + | ^^^^^^^^^^^^^^^ required by this bound in `verify` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.next.stderr new file mode 100644 index 00000000000..bcede8a255f --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.next.stderr @@ -0,0 +1,15 @@ +error[E0277]: Very important message! + --> $DIR/type_mismatch.rs:25:14 + | +LL | verify::<u8>(); + | ^^ the trait `TheImportantOne` is not implemented for `u8` + | +note: required by a bound in `verify` + --> $DIR/type_mismatch.rs:22:14 + | +LL | fn verify<T: TheImportantOne>() {} + | ^^^^^^^^^^^^^^^ required by this bound in `verify` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.rs b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.rs new file mode 100644 index 00000000000..d6721ccc848 --- /dev/null +++ b/tests/ui/diagnostic_namespace/do_not_recommend/type_mismatch.rs @@ -0,0 +1,27 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +#![feature(do_not_recommend)] + +#[diagnostic::on_unimplemented(message = "Very important message!")] +trait TheImportantOne {} + +trait ImplementationDetail { + type Restriction; +} + +#[diagnostic::do_not_recommend] +impl<T: ImplementationDetail<Restriction = ()>> TheImportantOne for T {} + +// Comment out this `impl` to show the expected error message. +impl ImplementationDetail for u8 { + type Restriction = u8; +} + +fn verify<T: TheImportantOne>() {} + +pub fn main() { + verify::<u8>(); + //~^ERROR: Very important message! [E0277] +} diff --git a/tests/ui/extern-flag/empty-extern-arg.stderr b/tests/ui/extern-flag/empty-extern-arg.stderr index 6ad3effe0e2..2785b12a0ae 100644 --- a/tests/ui/extern-flag/empty-extern-arg.stderr +++ b/tests/ui/extern-flag/empty-extern-arg.stderr @@ -1,6 +1,13 @@ error: extern location for std does not exist: +error: `#[panic_handler]` function required, but not found + +error: unwinding panics are not supported without std + | + = help: using nightly cargo, use -Zbuild-std with panic="abort" to avoid unwinding + = note: since the core library is usually precompiled with panic="unwind", rebuilding your crate with panic="abort" may not be enough to fix the problem + error: requires `sized` lang_item -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/extern-flag/no-nounused.rs b/tests/ui/extern-flag/no-nounused.rs index bed8006542c..30b66339876 100644 --- a/tests/ui/extern-flag/no-nounused.rs +++ b/tests/ui/extern-flag/no-nounused.rs @@ -2,5 +2,5 @@ //@ compile-flags: -Zunstable-options -Dunused-crate-dependencies //@ edition:2018 -fn main() { //~ ERROR external crate `somedep` unused in `no_nounused` +fn main() { //~ ERROR extern crate `somedep` is unused in crate `no_nounused` } diff --git a/tests/ui/extern-flag/no-nounused.stderr b/tests/ui/extern-flag/no-nounused.stderr index 171079287f0..2b42e851561 100644 --- a/tests/ui/extern-flag/no-nounused.stderr +++ b/tests/ui/extern-flag/no-nounused.stderr @@ -1,9 +1,10 @@ -error: external crate `somedep` unused in `no_nounused`: remove the dependency or add `use somedep as _;` +error: extern crate `somedep` is unused in crate `no_nounused` --> $DIR/no-nounused.rs:5:1 | LL | fn main() { | ^ | + = help: remove the dependency or add `use somedep as _;` to the crate root = note: requested on the command line with `-D unused-crate-dependencies` error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/feature-gate-extern_prelude.rs b/tests/ui/feature-gates/feature-gate-extern_prelude.rs deleted file mode 100644 index 237099e7901..00000000000 --- a/tests/ui/feature-gates/feature-gate-extern_prelude.rs +++ /dev/null @@ -1 +0,0 @@ -can-only-test-this-in-run-make-fulldeps //~ ERROR expected one of `!` or `::`, found `-` diff --git a/tests/ui/feature-gates/feature-gate-extern_prelude.stderr b/tests/ui/feature-gates/feature-gate-extern_prelude.stderr deleted file mode 100644 index 3b0ffae8696..00000000000 --- a/tests/ui/feature-gates/feature-gate-extern_prelude.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: expected one of `!` or `::`, found `-` - --> $DIR/feature-gate-extern_prelude.rs:1:4 - | -LL | can-only-test-this-in-run-make-fulldeps - | ^ expected one of `!` or `::` - -error: aborting due to 1 previous error - diff --git a/tests/ui/feature-gates/feature-gate-offset-of-slice.rs b/tests/ui/feature-gates/feature-gate-offset-of-slice.rs new file mode 100644 index 00000000000..23e8668bc68 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-offset-of-slice.rs @@ -0,0 +1,26 @@ +use std::mem::offset_of; + +struct S { + a: u8, + b: (u8, u8), + c: [i32], +} + +struct T { + x: i32, + y: S, +} + +type Tup = (i32, [i32]); + +fn main() { + offset_of!(S, c); //~ ERROR size for values of type `[i32]` cannot be known at compilation time +} + +fn other() { + offset_of!(T, y); //~ ERROR size for values of type `[i32]` cannot be known at compilation time +} + +fn tuple() { + offset_of!(Tup, 1); //~ ERROR size for values of type `[i32]` cannot be known at compilation time +} diff --git a/tests/ui/feature-gates/feature-gate-offset-of-slice.stderr b/tests/ui/feature-gates/feature-gate-offset-of-slice.stderr new file mode 100644 index 00000000000..5cf34a897f4 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-offset-of-slice.stderr @@ -0,0 +1,35 @@ +error[E0277]: the size for values of type `[i32]` cannot be known at compilation time + --> $DIR/feature-gate-offset-of-slice.rs:17:5 + | +LL | offset_of!(S, c); + | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[i32]` + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[i32]` cannot be known at compilation time + --> $DIR/feature-gate-offset-of-slice.rs:21:5 + | +LL | offset_of!(T, y); + | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `S`, the trait `Sized` is not implemented for `[i32]`, which is required by `S: Sized` +note: required because it appears within the type `S` + --> $DIR/feature-gate-offset-of-slice.rs:3:8 + | +LL | struct S { + | ^ + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[i32]` cannot be known at compilation time + --> $DIR/feature-gate-offset-of-slice.rs:25:5 + | +LL | offset_of!(Tup, 1); + | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[i32]` + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.rs b/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.rs deleted file mode 100644 index ed5db56e0e8..00000000000 --- a/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub fn main() { - if let Some(Some(&x)) = &Some(&Some(0)) { - //~^ ERROR: mismatched types [E0308] - let _: u32 = x; - } - if let Some(&Some(x)) = &Some(Some(0)) { - //~^ ERROR: mismatched types [E0308] - let _: u32 = x; - } - if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { - //~^ ERROR: mismatched types [E0308] - let _: u32 = x; - } -} diff --git a/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.stderr b/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.stderr deleted file mode 100644 index 0f0051325cd..00000000000 --- a/tests/ui/feature-gates/feature-gate-ref_pat_everywhere.stderr +++ /dev/null @@ -1,49 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/feature-gate-ref_pat_everywhere.rs:2:22 - | -LL | if let Some(Some(&x)) = &Some(&Some(0)) { - | ^^ --------------- this expression has type `&Option<&Option<{integer}>>` - | | - | expected integer, found `&_` - | - = note: expected type `{integer}` - found reference `&_` -help: consider removing `&` from the pattern - | -LL | if let Some(Some(x)) = &Some(&Some(0)) { - | ~ - -error[E0308]: mismatched types - --> $DIR/feature-gate-ref_pat_everywhere.rs:6:17 - | -LL | if let Some(&Some(x)) = &Some(Some(0)) { - | ^^^^^^^^ -------------- this expression has type `&Option<Option<{integer}>>` - | | - | expected `Option<{integer}>`, found `&_` - | - = note: expected enum `Option<{integer}>` - found reference `&_` - -error[E0308]: mismatched types - --> $DIR/feature-gate-ref_pat_everywhere.rs:10:22 - | -LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { - | ^^^^^^ ----------------------- this expression has type `&mut Option<&mut Option<{integer}>>` - | | - | expected integer, found `&mut _` - | - = note: expected type `{integer}` - found mutable reference `&mut _` -note: to declare a mutable binding use: `mut x` - --> $DIR/feature-gate-ref_pat_everywhere.rs:10:22 - | -LL | if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { - | ^^^^^^ -help: consider removing `&mut` from the pattern - | -LL | if let Some(Some(x)) = &mut Some(&mut Some(0)) { - | ~ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/feature-gates/feature-gate-unsafe-attributes.rs b/tests/ui/feature-gates/feature-gate-unsafe-attributes.rs new file mode 100644 index 00000000000..9eba415dda0 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unsafe-attributes.rs @@ -0,0 +1,8 @@ +#[unsafe(no_mangle)] //~ ERROR [E0658] +extern "C" fn foo() { + +} + +fn main() { + foo(); +} diff --git a/tests/ui/feature-gates/feature-gate-unsafe-attributes.stderr b/tests/ui/feature-gates/feature-gate-unsafe-attributes.stderr new file mode 100644 index 00000000000..dfcea756b02 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unsafe-attributes.stderr @@ -0,0 +1,13 @@ +error[E0658]: `#[unsafe()]` markers for attributes are experimental + --> $DIR/feature-gate-unsafe-attributes.rs:1:3 + | +LL | #[unsafe(no_mangle)] + | ^^^^^^ + | + = note: see issue #123757 <https://github.com/rust-lang/rust/issues/123757> for more information + = help: add `#![feature(unsafe_attributes)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs new file mode 100644 index 00000000000..eab134a4a4d --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.rs @@ -0,0 +1,5 @@ +unsafe extern "C" { + //~^ ERROR extern block cannot be declared unsafe +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr new file mode 100644 index 00000000000..7e9b199a2db --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unsafe-extern-blocks.stderr @@ -0,0 +1,8 @@ +error: extern block cannot be declared unsafe + --> $DIR/feature-gate-unsafe-extern-blocks.rs:1:1 + | +LL | unsafe extern "C" { + | ^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/feature-gates/feature-gate-vectorcall.stderr b/tests/ui/feature-gates/feature-gate-vectorcall.stderr index df93e8812c1..b20e41887b9 100644 --- a/tests/ui/feature-gates/feature-gate-vectorcall.stderr +++ b/tests/ui/feature-gates/feature-gate-vectorcall.stderr @@ -4,6 +4,7 @@ error[E0658]: vectorcall is experimental and subject to change LL | extern "vectorcall" fn f() {} | ^^^^^^^^^^^^ | + = note: see issue #124485 <https://github.com/rust-lang/rust/issues/124485> for more information = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date @@ -13,6 +14,7 @@ error[E0658]: vectorcall is experimental and subject to change LL | extern "vectorcall" fn m(); | ^^^^^^^^^^^^ | + = note: see issue #124485 <https://github.com/rust-lang/rust/issues/124485> for more information = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date @@ -22,6 +24,7 @@ error[E0658]: vectorcall is experimental and subject to change LL | extern "vectorcall" fn dm() {} | ^^^^^^^^^^^^ | + = note: see issue #124485 <https://github.com/rust-lang/rust/issues/124485> for more information = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date @@ -31,6 +34,7 @@ error[E0658]: vectorcall is experimental and subject to change LL | extern "vectorcall" fn m() {} | ^^^^^^^^^^^^ | + = note: see issue #124485 <https://github.com/rust-lang/rust/issues/124485> for more information = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date @@ -40,6 +44,7 @@ error[E0658]: vectorcall is experimental and subject to change LL | extern "vectorcall" fn im() {} | ^^^^^^^^^^^^ | + = note: see issue #124485 <https://github.com/rust-lang/rust/issues/124485> for more information = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date @@ -49,6 +54,7 @@ error[E0658]: vectorcall is experimental and subject to change LL | type TA = extern "vectorcall" fn(); | ^^^^^^^^^^^^ | + = note: see issue #124485 <https://github.com/rust-lang/rust/issues/124485> for more information = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date @@ -58,6 +64,7 @@ error[E0658]: vectorcall is experimental and subject to change LL | extern "vectorcall" {} | ^^^^^^^^^^^^ | + = note: see issue #124485 <https://github.com/rust-lang/rust/issues/124485> for more information = help: add `#![feature(abi_vectorcall)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date diff --git a/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs b/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs index 671d17f36f1..285493132b6 100644 --- a/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs +++ b/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.rs @@ -9,7 +9,6 @@ impl<T> X for T { //~ ERROR: not all trait items implemented //~^ ERROR missing generics for associated type //~^^ ERROR missing generics for associated type //~| ERROR method `foo` has 1 type parameter but its trait declaration has 0 type parameters - //~| ERROR may not live long enough t } } diff --git a/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr b/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr index 65854ed7158..6a600aee11f 100644 --- a/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr +++ b/tests/ui/generic-associated-types/gat-trait-path-missing-lifetime.stderr @@ -51,16 +51,7 @@ help: add missing lifetime argument LL | fn foo<'a, T1: X<Y<'a> = T1>>(t : T1) -> T1::Y<'a> { | ++++ -error: lifetime may not live long enough - --> $DIR/gat-trait-path-missing-lifetime.rs:8:3 - | -LL | fn foo<'a, T1: X<Y = T1>>(t : T1) -> T1::Y<'a> { - | ^^^^^^^--^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | | - | | lifetime `'a` defined here - | requires that `'a` must outlive `'static` - -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0046, E0049, E0107. For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/generic-associated-types/issue-70304.rs b/tests/ui/generic-associated-types/issue-70304.rs index 935d3f7a4ba..8898d4c7d13 100644 --- a/tests/ui/generic-associated-types/issue-70304.rs +++ b/tests/ui/generic-associated-types/issue-70304.rs @@ -52,5 +52,4 @@ fn create_doc() -> impl Document<Cursor<'_> = DocCursorImpl<'_>> { pub fn main() { let doc = create_doc(); let lexer: Lexer<'_, DocCursorImpl<'_>> = Lexer::from(&doc); - //~^ ERROR: `doc` does not live long enough } diff --git a/tests/ui/generic-associated-types/issue-70304.stderr b/tests/ui/generic-associated-types/issue-70304.stderr index 8e012cc6d93..9b02c1b0768 100644 --- a/tests/ui/generic-associated-types/issue-70304.stderr +++ b/tests/ui/generic-associated-types/issue-70304.stderr @@ -27,21 +27,7 @@ LL | type Cursor<'a>: DocCursor<'a>; = note: this bound is currently required to ensure that impls have maximum flexibility = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information -error[E0597]: `doc` does not live long enough - --> $DIR/issue-70304.rs:54:59 - | -LL | let doc = create_doc(); - | --- binding `doc` declared here -LL | let lexer: Lexer<'_, DocCursorImpl<'_>> = Lexer::from(&doc); - | ------------^^^^- - | | | - | | borrowed value does not live long enough - | argument requires that `doc` is borrowed for `'static` -LL | -LL | } - | - `doc` dropped here while still borrowed - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0106, E0597, E0637. +Some errors have detailed explanations: E0106, E0637. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/generic-associated-types/issue-71176.rs b/tests/ui/generic-associated-types/issue-71176.rs index f0e162d825f..e58b6f6091e 100644 --- a/tests/ui/generic-associated-types/issue-71176.rs +++ b/tests/ui/generic-associated-types/issue-71176.rs @@ -9,6 +9,9 @@ impl Provider for () { struct Holder<B> { inner: Box<dyn Provider<A = B>>, //~^ ERROR: missing generics for associated type + //~| ERROR: missing generics for associated type + //~| ERROR: missing generics for associated type + //~| ERROR: the trait `Provider` cannot be made into an object } fn main() { diff --git a/tests/ui/generic-associated-types/issue-71176.stderr b/tests/ui/generic-associated-types/issue-71176.stderr index ed837f34753..a1913bb618b 100644 --- a/tests/ui/generic-associated-types/issue-71176.stderr +++ b/tests/ui/generic-associated-types/issue-71176.stderr @@ -14,6 +14,57 @@ help: add missing lifetime argument LL | inner: Box<dyn Provider<A<'a> = B>>, | ++++ -error: aborting due to 1 previous error +error[E0107]: missing generics for associated type `Provider::A` + --> $DIR/issue-71176.rs:10:27 + | +LL | inner: Box<dyn Provider<A = B>>, + | ^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'a` + --> $DIR/issue-71176.rs:2:10 + | +LL | type A<'a>; + | ^ -- + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing lifetime argument + | +LL | inner: Box<dyn Provider<A<'a> = B>>, + | ++++ + +error[E0107]: missing generics for associated type `Provider::A` + --> $DIR/issue-71176.rs:10:27 + | +LL | inner: Box<dyn Provider<A = B>>, + | ^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'a` + --> $DIR/issue-71176.rs:2:10 + | +LL | type A<'a>; + | ^ -- + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: add missing lifetime argument + | +LL | inner: Box<dyn Provider<A<'a> = B>>, + | ++++ + +error[E0038]: the trait `Provider` cannot be made into an object + --> $DIR/issue-71176.rs:10:14 + | +LL | inner: Box<dyn Provider<A = B>>, + | ^^^^^^^^^^^^^^^^^^^ `Provider` 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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/issue-71176.rs:2:10 + | +LL | trait Provider { + | -------- this trait cannot be made into an object... +LL | type A<'a>; + | ^ ...because it contains the generic associated type `A` + = help: consider moving `A` to another trait + = help: only type `()` implements the trait, consider using it directly instead + +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0038, E0107. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/generic-associated-types/issue-80433.rs b/tests/ui/generic-associated-types/issue-80433.rs index 53057542440..bdba78c2ccd 100644 --- a/tests/ui/generic-associated-types/issue-80433.rs +++ b/tests/ui/generic-associated-types/issue-80433.rs @@ -22,8 +22,7 @@ fn test_simpler<'a>(dst: &'a mut impl TestMut<Output = &'a mut f32>) //~^ ERROR missing generics for associated type { for n in 0i16..100 { - *dst.test_mut() = n.into(); //~ ERROR: cannot borrow - //~^ ERROR: borrowed data escapes outside of function + *dst.test_mut() = n.into(); } } diff --git a/tests/ui/generic-associated-types/issue-80433.stderr b/tests/ui/generic-associated-types/issue-80433.stderr index a9a14d3f51c..8ab6fdcb815 100644 --- a/tests/ui/generic-associated-types/issue-80433.stderr +++ b/tests/ui/generic-associated-types/issue-80433.stderr @@ -25,30 +25,6 @@ help: add missing lifetime argument LL | fn test_simpler<'a>(dst: &'a mut impl TestMut<Output<'a> = &'a mut f32>) | ++++ -error[E0499]: cannot borrow `*dst` as mutable more than once at a time - --> $DIR/issue-80433.rs:25:10 - | -LL | *dst.test_mut() = n.into(); - | ^^^----------- - | | - | `*dst` was mutably borrowed here in the previous iteration of the loop - | argument requires that `*dst` is borrowed for `'static` - -error[E0521]: borrowed data escapes outside of function - --> $DIR/issue-80433.rs:25:10 - | -LL | fn test_simpler<'a>(dst: &'a mut impl TestMut<Output = &'a mut f32>) - | -- --- `dst` is a reference that is only valid in the function body - | | - | lifetime `'a` defined here -... -LL | *dst.test_mut() = n.into(); - | ^^^^^^^^^^^^^^ - | | - | `dst` escapes the function body here - | argument requires that `'a` must outlive `'static` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0107, E0499, E0521. -For more information about an error, try `rustc --explain E0107`. +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr b/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr new file mode 100644 index 00000000000..14a3d5e178d --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr @@ -0,0 +1,9 @@ +error[E0284]: type annotations needed: cannot satisfy `for<'a> <_ as Trait<'a>>::Assoc <: <T as Trait<'_>>::Assoc` + --> $DIR/rigid-equate-projections-in-higher-ranked-fn-signature.rs:27:50 + | +LL | let _: for<'a> fn(<_ as Trait<'a>>::Assoc) = foo::<T>(); + | ^^^^^^^^^^ cannot satisfy `for<'a> <_ as Trait<'a>>::Assoc <: <T as Trait<'_>>::Assoc` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.rs b/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.rs new file mode 100644 index 00000000000..10dbc2a4a82 --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.rs @@ -0,0 +1,30 @@ +//@ revisions: current next +//@[current] check-pass +//@[next] compile-flags: -Znext-solver +//@[next] check-fail +//@ ignore-compare-mode-next-solver (explicit revisions) + +/// This triggers an ICE with (and without) `--emit metadata` using the old +/// trait solver: +/// ``` +/// rustc +nightly-2023-01-09 \ +/// tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.rs +/// ``` +/// The ICE was unknowingly fixed by +/// <https://github.com/rust-lang/rust/pull/101947> in `nightly-2023-01-10`. +/// This is a regression test for that fixed ICE. For the next solver we simply +/// make sure there is a compiler error. + +trait Trait<'a> { + type Assoc; +} + +fn foo<T: for<'a> Trait<'a>>() -> for<'a> fn(<T as Trait<'a>>::Assoc) { + todo!() +} + +fn bar<T: for<'a> Trait<'a>>() { + let _: for<'a> fn(<_ as Trait<'a>>::Assoc) = foo::<T>(); //[next]~ ERROR type annotations needed +} + +fn main() {} diff --git a/tests/ui/impl-header-lifetime-elision/assoc-type.rs b/tests/ui/impl-header-lifetime-elision/assoc-type.rs index b0089a37aa0..db3c416540f 100644 --- a/tests/ui/impl-header-lifetime-elision/assoc-type.rs +++ b/tests/ui/impl-header-lifetime-elision/assoc-type.rs @@ -9,7 +9,7 @@ trait MyTrait { impl MyTrait for &i32 { type Output = &i32; - //~^ ERROR `&` without an explicit lifetime name cannot be used here + //~^ ERROR 11:19: 11:20: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type } impl MyTrait for &u32 { diff --git a/tests/ui/impl-header-lifetime-elision/assoc-type.stderr b/tests/ui/impl-header-lifetime-elision/assoc-type.stderr index c4f27e0b80e..e650eeca48a 100644 --- a/tests/ui/impl-header-lifetime-elision/assoc-type.stderr +++ b/tests/ui/impl-header-lifetime-elision/assoc-type.stderr @@ -1,8 +1,8 @@ -error[E0637]: `&` without an explicit lifetime name cannot be used here +error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type --> $DIR/assoc-type.rs:11:19 | LL | type Output = &i32; - | ^ explicit lifetime name needed here + | ^ this lifetime must come from the implemented type error[E0637]: `'_` cannot be used here --> $DIR/assoc-type.rs:16:20 diff --git a/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness-2.rs b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness-2.rs new file mode 100644 index 00000000000..65e90c1ca53 --- /dev/null +++ b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness-2.rs @@ -0,0 +1,38 @@ +// This test should never pass! + +#![feature(type_alias_impl_trait)] + +pub trait Captures<'a> {} +impl<T> Captures<'_> for T {} + +pub struct MyTy<'a, 'b>(Option<*mut &'a &'b ()>); +unsafe impl Send for MyTy<'_, 'static> {} + +pub mod step1 { + use super::*; + pub type Step1<'a, 'b: 'a> = impl Sized + Captures<'b> + 'a; + pub fn step1<'a, 'b: 'a>() -> Step1<'a, 'b> { + MyTy::<'a, 'b>(None) + } +} + +pub mod step2 { + pub type Step2<'a> = impl Send + 'a; + + // Although `Step2` is WF at the definition site, it's not WF in its + // declaration site (above). We check this in `check_opaque_meets_bounds`, + // which must remain sound. + pub fn step2<'a, 'b: 'a>() -> Step2<'a> + where crate::step1::Step1<'a, 'b>: Send + { + crate::step1::step1::<'a, 'b>() + //~^ ERROR hidden type for `Step2<'a>` captures lifetime that does not appear in bounds + } +} + +fn step3<'a, 'b>() { + fn is_send<T: Send>() {} + is_send::<crate::step2::Step2::<'a>>(); +} + +fn main() {} diff --git a/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness-2.stderr b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness-2.stderr new file mode 100644 index 00000000000..58d7f9959d3 --- /dev/null +++ b/tests/ui/impl-trait/alias-liveness/tait-hidden-erased-unsoundness-2.stderr @@ -0,0 +1,15 @@ +error[E0700]: hidden type for `Step2<'a>` captures lifetime that does not appear in bounds + --> $DIR/tait-hidden-erased-unsoundness-2.rs:28:9 + | +LL | pub type Step2<'a> = impl Send + 'a; + | -------------- opaque type defined here +... +LL | pub fn step2<'a, 'b: 'a>() -> Step2<'a> + | -- hidden type `Step1<'a, 'b>` captures the lifetime `'b` as defined here +... +LL | crate::step1::step1::<'a, 'b>() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0700`. diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.rs b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.rs index 5b3a4eb53ff..14b1ebea8db 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.rs +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.rs @@ -1,11 +1,9 @@ // issue: 114146 - trait Foo { fn bar<'other: 'a>() -> impl Sized + 'a {} //~^ ERROR use of undeclared lifetime name `'a` //~| ERROR use of undeclared lifetime name `'a` - //~| ERROR expected generic lifetime parameter, found `'static` } fn main() {} diff --git a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr index 8975578dabd..f1b006da1db 100644 --- a/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr +++ b/tests/ui/impl-trait/in-trait/bad-item-bound-within-rpitit-2.stderr @@ -1,5 +1,5 @@ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/bad-item-bound-within-rpitit-2.rs:5:20 + --> $DIR/bad-item-bound-within-rpitit-2.rs:4:20 | LL | fn bar<'other: 'a>() -> impl Sized + 'a {} | ^^ undeclared lifetime @@ -14,7 +14,7 @@ LL | trait Foo<'a> { | ++++ error[E0261]: use of undeclared lifetime name `'a` - --> $DIR/bad-item-bound-within-rpitit-2.rs:5:42 + --> $DIR/bad-item-bound-within-rpitit-2.rs:4:42 | LL | fn bar<'other: 'a>() -> impl Sized + 'a {} | ^^ undeclared lifetime @@ -28,15 +28,6 @@ help: consider introducing lifetime `'a` here LL | trait Foo<'a> { | ++++ -error[E0792]: expected generic lifetime parameter, found `'static` - --> $DIR/bad-item-bound-within-rpitit-2.rs:5:45 - | -LL | fn bar<'other: 'a>() -> impl Sized + 'a {} - | ------ ^^ - | | - | cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0261, E0792. -For more information about an error, try `rustc --explain E0261`. +For more information about this error, try `rustc --explain E0261`. diff --git a/tests/ui/impl-trait/issues/issue-67830.rs b/tests/ui/impl-trait/issues/issue-67830.rs index 939eca82a8f..28772fa5272 100644 --- a/tests/ui/impl-trait/issues/issue-67830.rs +++ b/tests/ui/impl-trait/issues/issue-67830.rs @@ -7,7 +7,7 @@ struct Wrap<F>(F); impl<A, B, F> MyFn<A> for Wrap<F> where - F: Fn(A) -> B + F: Fn(A) -> B, { type Output = B; @@ -16,13 +16,10 @@ where } } - struct A; -fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> { +fn test() -> impl for<'a> MyFn<&'a A, Output = impl Iterator + 'a> { //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` Wrap(|a| Some(a).into_iter()) - //~^ ERROR implementation of `FnOnce` is not general enough - //~| ERROR implementation of `FnOnce` is not general enough } fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-67830.stderr b/tests/ui/impl-trait/issues/issue-67830.stderr index ef513a40cf3..a7633c7f20b 100644 --- a/tests/ui/impl-trait/issues/issue-67830.stderr +++ b/tests/ui/impl-trait/issues/issue-67830.stderr @@ -1,34 +1,15 @@ error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/issue-67830.rs:21:62 + --> $DIR/issue-67830.rs:20:64 | -LL | fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> { - | ^^ +LL | fn test() -> impl for<'a> MyFn<&'a A, Output = impl Iterator + 'a> { + | ^^ | note: lifetime declared here - --> $DIR/issue-67830.rs:21:23 + --> $DIR/issue-67830.rs:20:23 | -LL | fn test() -> impl for<'a> MyFn<&'a A, Output=impl Iterator + 'a> { +LL | fn test() -> impl for<'a> MyFn<&'a A, Output = impl Iterator + 'a> { | ^^ -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-67830.rs:23:5 - | -LL | Wrap(|a| Some(a).into_iter()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 A) -> std::option::IntoIter<&A>` must implement `FnOnce<(&'1 A,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 A,)>`, for some specific lifetime `'2` - -error: implementation of `FnOnce` is not general enough - --> $DIR/issue-67830.rs:23:5 - | -LL | Wrap(|a| Some(a).into_iter()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough - | - = note: closure with signature `fn(&'2 A) -> std::option::IntoIter<&A>` must implement `FnOnce<(&'1 A,)>`, for any lifetime `'1`... - = note: ...but it actually implements `FnOnce<(&'2 A,)>`, for some specific lifetime `'2` - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0657`. diff --git a/tests/ui/impl-trait/issues/issue-88236-2.rs b/tests/ui/impl-trait/issues/issue-88236-2.rs index 7ff08d8174f..5005af46ee1 100644 --- a/tests/ui/impl-trait/issues/issue-88236-2.rs +++ b/tests/ui/impl-trait/issues/issue-88236-2.rs @@ -18,16 +18,11 @@ fn make_impl() -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> {} fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` &() - //~^ ERROR implementation of `Hrtb` is not general enough - //~| ERROR implementation of `Hrtb` is not general enough } fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` x - //~^ ERROR implementation of `Hrtb` is not general enough - //~| ERROR implementation of `Hrtb` is not general enough - //~| ERROR lifetime may not live long enough } fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-88236-2.stderr b/tests/ui/impl-trait/issues/issue-88236-2.stderr index 09fd58056a5..4ded9ed386f 100644 --- a/tests/ui/impl-trait/issues/issue-88236-2.stderr +++ b/tests/ui/impl-trait/issues/issue-88236-2.stderr @@ -22,72 +22,18 @@ note: lifetime declared here LL | fn make_weird_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { | ^^ -error: implementation of `Hrtb` is not general enough - --> $DIR/issue-88236-2.rs:20:5 - | -LL | &() - | ^^^ implementation of `Hrtb` is not general enough - | - = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`... - = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1` - -error: implementation of `Hrtb` is not general enough - --> $DIR/issue-88236-2.rs:20:5 - | -LL | &() - | ^^^ implementation of `Hrtb` is not general enough - | - = note: `Hrtb<'a>` would have to be implemented for the type `&()` - = note: ...but `Hrtb<'0>` is actually implemented for the type `&'0 ()`, for some specific lifetime `'0` - error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/issue-88236-2.rs:25:78 + --> $DIR/issue-88236-2.rs:23:78 | LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { | ^^ | note: lifetime declared here - --> $DIR/issue-88236-2.rs:25:45 + --> $DIR/issue-88236-2.rs:23:45 | LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { | ^^ -error: lifetime may not live long enough - --> $DIR/issue-88236-2.rs:27:5 - | -LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> { - | -- lifetime `'b` defined here -LL | -LL | x - | ^ returning this value requires that `'b` must outlive `'static` - | -help: to declare that `impl for<'a> Hrtb<'a, Assoc = impl Send + '_>` captures data from argument `x`, you can add an explicit `'b` lifetime bound - | -LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a> + 'b { - | ++++ -help: to declare that `impl Send + 'a` captures data from argument `x`, you can add an explicit `'b` lifetime bound - | -LL | fn make_bad_impl<'b>(x: &'b ()) -> impl for<'a> Hrtb<'a, Assoc = impl Send + 'a + 'b> { - | ++++ - -error: implementation of `Hrtb` is not general enough - --> $DIR/issue-88236-2.rs:27:5 - | -LL | x - | ^ implementation of `Hrtb` is not general enough - | - = note: `Hrtb<'0>` would have to be implemented for the type `&()`, for any lifetime `'0`... - = note: ...but `Hrtb<'1>` is actually implemented for the type `&'1 ()`, for some specific lifetime `'1` - -error: implementation of `Hrtb` is not general enough - --> $DIR/issue-88236-2.rs:27:5 - | -LL | x - | ^ implementation of `Hrtb` is not general enough - | - = note: `Hrtb<'a>` would have to be implemented for the type `&()` - = note: ...but `Hrtb<'0>` is actually implemented for the type `&'0 ()`, for some specific lifetime `'0` - -error: aborting due to 8 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0657`. diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.rs b/tests/ui/impl-trait/nested-rpit-hrtb.rs index 9b18aceb4a7..11d79bcff73 100644 --- a/tests/ui/impl-trait/nested-rpit-hrtb.rs +++ b/tests/ui/impl-trait/nested-rpit-hrtb.rs @@ -31,7 +31,6 @@ fn one_hrtb_trait_param() -> impl for<'a> Foo<'a, Assoc = impl Qux<'a>> {} fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {} //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` -//~| ERROR implementation of `Bar` is not general enough fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} //~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` @@ -64,6 +63,5 @@ fn two_htrb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Qux< // `'b` is not in scope for the outlives bound. fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {} //~^ ERROR use of undeclared lifetime name `'b` [E0261] -//~| ERROR implementation of `Bar` is not general enough fn main() {} diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.stderr b/tests/ui/impl-trait/nested-rpit-hrtb.stderr index 2fa036f35fa..d98de650d0d 100644 --- a/tests/ui/impl-trait/nested-rpit-hrtb.stderr +++ b/tests/ui/impl-trait/nested-rpit-hrtb.stderr @@ -1,5 +1,5 @@ error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/nested-rpit-hrtb.rs:57:77 + --> $DIR/nested-rpit-hrtb.rs:56:77 | LL | fn two_htrb_outlives() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Sized + 'b> {} | ^^ undeclared lifetime @@ -15,7 +15,7 @@ LL | fn two_htrb_outlives<'b>() -> impl for<'a> Foo<'a, Assoc = impl for<'b> Siz | ++++ error[E0261]: use of undeclared lifetime name `'b` - --> $DIR/nested-rpit-hrtb.rs:65:82 + --> $DIR/nested-rpit-hrtb.rs:64:82 | LL | fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {} | ^^ undeclared lifetime @@ -65,29 +65,20 @@ note: lifetime declared here LL | fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {} | ^^ -error: implementation of `Bar` is not general enough - --> $DIR/nested-rpit-hrtb.rs:32:78 - | -LL | fn one_hrtb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'a> {} - | ^^ implementation of `Bar` is not general enough - | - = note: `()` must implement `Bar<'a>` - = note: ...but it actually implements `Bar<'0>`, for some specific lifetime `'0` - error[E0657]: `impl Trait` cannot capture higher-ranked lifetime from outer `impl Trait` - --> $DIR/nested-rpit-hrtb.rs:36:73 + --> $DIR/nested-rpit-hrtb.rs:35:73 | LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} | ^^ | note: lifetime declared here - --> $DIR/nested-rpit-hrtb.rs:36:44 + --> $DIR/nested-rpit-hrtb.rs:35:44 | LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} | ^^ error[E0277]: the trait bound `for<'a> &'a (): Qux<'b>` is not satisfied - --> $DIR/nested-rpit-hrtb.rs:46:79 + --> $DIR/nested-rpit-hrtb.rs:45:79 | LL | fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Qux<'b>> {} | ^^^^^^^^^^^^ the trait `for<'a> Qux<'b>` is not implemented for `&'a ()` @@ -96,7 +87,7 @@ LL | fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = help: for that trait implementation, expected `()`, found `&'a ()` error: implementation of `Bar` is not general enough - --> $DIR/nested-rpit-hrtb.rs:50:93 + --> $DIR/nested-rpit-hrtb.rs:49:93 | LL | fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'b> {} | ^^ implementation of `Bar` is not general enough @@ -105,7 +96,7 @@ LL | fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = = note: ...but it actually implements `Bar<'0>`, for some specific lifetime `'0` error[E0277]: the trait bound `for<'a, 'b> &'a (): Qux<'b>` is not satisfied - --> $DIR/nested-rpit-hrtb.rs:61:64 + --> $DIR/nested-rpit-hrtb.rs:60:64 | LL | fn two_htrb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Qux<'b>> {} | ^^^^^^^^^^^^^^^^^^^^ the trait `for<'a, 'b> Qux<'b>` is not implemented for `&'a ()` @@ -113,16 +104,7 @@ LL | fn two_htrb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> = help: the trait `Qux<'_>` is implemented for `()` = help: for that trait implementation, expected `()`, found `&'a ()` -error: implementation of `Bar` is not general enough - --> $DIR/nested-rpit-hrtb.rs:65:86 - | -LL | fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Sized + 'b> {} - | ^^ implementation of `Bar` is not general enough - | - = note: `()` must implement `Bar<'a>` - = note: ...but it actually implements `Bar<'0>`, for some specific lifetime `'0` - -error: aborting due to 11 previous errors +error: aborting due to 9 previous errors Some errors have detailed explanations: E0261, E0277, E0657. For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/imports/cycle-import-in-diff-module-0.rs b/tests/ui/imports/cycle-import-in-diff-module-0.rs new file mode 100644 index 00000000000..962603a8971 --- /dev/null +++ b/tests/ui/imports/cycle-import-in-diff-module-0.rs @@ -0,0 +1,14 @@ +//@ check-pass + +// https://github.com/rust-lang/rust/pull/124840#issuecomment-2098148587 + +mod a { + pub(crate) use crate::S; +} +mod b { + pub struct S; +} +use self::a::S; +use self::b::*; + +fn main() {} diff --git a/tests/ui/imports/cycle-import-in-diff-module-1.rs b/tests/ui/imports/cycle-import-in-diff-module-1.rs new file mode 100644 index 00000000000..8c67df376c3 --- /dev/null +++ b/tests/ui/imports/cycle-import-in-diff-module-1.rs @@ -0,0 +1,14 @@ +//@ check-pass + +// similar `cycle-import-in-diff-module-0.rs` + +mod a { + pub(crate) use crate::s; +} +mod b { + pub mod s {} +} +use self::b::*; +use self::a::s; + +fn main() {} diff --git a/tests/ui/imports/cycle-import-in-std-1.rs b/tests/ui/imports/cycle-import-in-std-1.rs new file mode 100644 index 00000000000..2fa492c155d --- /dev/null +++ b/tests/ui/imports/cycle-import-in-std-1.rs @@ -0,0 +1,9 @@ +//@ edition: 2018 + +// https://github.com/rust-lang/rust/issues/124490 + +use ops::{self as std}; +//~^ ERROR: unresolved import `ops` +use std::collections::{self as ops}; + +fn main() {} diff --git a/tests/ui/imports/cycle-import-in-std-1.stderr b/tests/ui/imports/cycle-import-in-std-1.stderr new file mode 100644 index 00000000000..d4e6f32cc10 --- /dev/null +++ b/tests/ui/imports/cycle-import-in-std-1.stderr @@ -0,0 +1,13 @@ +error[E0432]: unresolved import `ops` + --> $DIR/cycle-import-in-std-1.rs:5:11 + | +LL | use ops::{self as std}; + | ^^^^^^^^^^^ no external crate `ops` + | + = help: consider importing one of these items instead: + core::ops + std::ops + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/cycle-import-in-std-2.rs b/tests/ui/imports/cycle-import-in-std-2.rs new file mode 100644 index 00000000000..d73c57944bc --- /dev/null +++ b/tests/ui/imports/cycle-import-in-std-2.rs @@ -0,0 +1,9 @@ +//@ edition: 2018 + +// https://github.com/rust-lang/rust/issues/125013 + +use ops::{self as std}; +//~^ ERROR: unresolved import `ops` +use std::ops::Deref::{self as ops}; + +fn main() {} diff --git a/tests/ui/imports/cycle-import-in-std-2.stderr b/tests/ui/imports/cycle-import-in-std-2.stderr new file mode 100644 index 00000000000..dc0270dffe4 --- /dev/null +++ b/tests/ui/imports/cycle-import-in-std-2.stderr @@ -0,0 +1,13 @@ +error[E0432]: unresolved import `ops` + --> $DIR/cycle-import-in-std-2.rs:5:11 + | +LL | use ops::{self as std}; + | ^^^^^^^^^^^ no external crate `ops` + | + = help: consider importing one of these items instead: + core::ops + std::ops + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/shadow-glob-module-resolution-1.rs b/tests/ui/imports/shadow-glob-module-resolution-1.rs new file mode 100644 index 00000000000..ba1e65cddc6 --- /dev/null +++ b/tests/ui/imports/shadow-glob-module-resolution-1.rs @@ -0,0 +1,17 @@ +// https://github.com/rust-lang/rust/issues/124490 + +mod a { + pub mod b { + pub mod c {} + } +} + +use a::*; + +use b::c; +//~^ ERROR: cannot determine resolution for the import +//~| ERROR: cannot determine resolution for the import +//~| ERROR: unresolved import `b::c` +use c as b; + +fn main() {} diff --git a/tests/ui/imports/shadow-glob-module-resolution-1.stderr b/tests/ui/imports/shadow-glob-module-resolution-1.stderr new file mode 100644 index 00000000000..f9135963fe9 --- /dev/null +++ b/tests/ui/imports/shadow-glob-module-resolution-1.stderr @@ -0,0 +1,23 @@ +error: cannot determine resolution for the import + --> $DIR/shadow-glob-module-resolution-1.rs:11:5 + | +LL | use b::c; + | ^^^^ + +error: cannot determine resolution for the import + --> $DIR/shadow-glob-module-resolution-1.rs:11:5 + | +LL | use b::c; + | ^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0432]: unresolved import `b::c` + --> $DIR/shadow-glob-module-resolution-1.rs:11:5 + | +LL | use b::c; + | ^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/shadow-glob-module-resolution-2.rs b/tests/ui/imports/shadow-glob-module-resolution-2.rs new file mode 100644 index 00000000000..36bd72658ae --- /dev/null +++ b/tests/ui/imports/shadow-glob-module-resolution-2.rs @@ -0,0 +1,19 @@ +// https://github.com/rust-lang/rust/issues/125013 + +mod a { + pub mod b { + pub mod c { + pub trait D {} + } + } +} + +use a::*; + +use e as b; +//~^ ERROR: unresolved import `e` +use b::c::D as e; +//~^ ERROR: cannot determine resolution for the import +//~| ERROR: cannot determine resolution for the import + +fn main() { } diff --git a/tests/ui/imports/shadow-glob-module-resolution-2.stderr b/tests/ui/imports/shadow-glob-module-resolution-2.stderr new file mode 100644 index 00000000000..644fcb84162 --- /dev/null +++ b/tests/ui/imports/shadow-glob-module-resolution-2.stderr @@ -0,0 +1,26 @@ +error: cannot determine resolution for the import + --> $DIR/shadow-glob-module-resolution-2.rs:15:5 + | +LL | use b::c::D as e; + | ^^^^^^^^^^^^ + +error: cannot determine resolution for the import + --> $DIR/shadow-glob-module-resolution-2.rs:15:5 + | +LL | use b::c::D as e; + | ^^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0432]: unresolved import `e` + --> $DIR/shadow-glob-module-resolution-2.rs:13:5 + | +LL | use e as b; + | -^^^^^ + | | + | no `e` in the root + | help: a similar name exists in the module: `a` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/inline-const/const_block_pat_liveness.rs b/tests/ui/inline-const/const_block_pat_liveness.rs new file mode 100644 index 00000000000..26393a4f65b --- /dev/null +++ b/tests/ui/inline-const/const_block_pat_liveness.rs @@ -0,0 +1,18 @@ +//! This test used to ICE because const blocks didn't have a body +//! anymore, making a lot of logic very fragile around handling the +//! HIR of a const block. +//! https://github.com/rust-lang/rust/issues/125846 + +//@ check-pass + +#![feature(inline_const_pat)] + +fn main() { + match 0 { + const { + let a = 10_usize; + *&a + } + | _ => {} + } +} diff --git a/tests/ui/io-checks/non-ice-error-on-worker-io-fail.stderr b/tests/ui/io-checks/non-ice-error-on-worker-io-fail.stderr index 5775a4032c3..48cae82feb0 100644 --- a/tests/ui/io-checks/non-ice-error-on-worker-io-fail.stderr +++ b/tests/ui/io-checks/non-ice-error-on-worker-io-fail.stderr @@ -1,6 +1,4 @@ -warning: ignoring --out-dir flag due to -o flag - error: io error modifying ./does-not-exist/ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-28344.stderr b/tests/ui/issues/issue-28344.stderr index ddc1027c16b..d30fb3cfe58 100644 --- a/tests/ui/issues/issue-28344.stderr +++ b/tests/ui/issues/issue-28344.stderr @@ -52,7 +52,7 @@ error[E0599]: no function or associated item named `bitor` found for trait objec LL | let g = BitXor::bitor; | ^^^^^ function or associated item not found in `dyn BitXor<_>` | -help: there is a method `bitxor` with a similar name, but with different arguments +help: there is a method `bitxor` with a similar name --> $SRC_DIR/core/src/ops/bit.rs:LL:COL error: aborting due to 4 previous errors; 2 warnings emitted diff --git a/tests/ui/issues/issue-50781.rs b/tests/ui/issues/issue-50781.rs index 3c5e5a9f69a..32253c3c236 100644 --- a/tests/ui/issues/issue-50781.rs +++ b/tests/ui/issues/issue-50781.rs @@ -1,10 +1,7 @@ -#![deny(where_clauses_object_safety)] - trait Trait {} trait X { - fn foo(&self) where Self: Trait; //~ ERROR the trait `X` cannot be made into an object - //~^ WARN this was previously accepted by the compiler but is being phased out + fn foo(&self) where Self: Trait; } impl X for () { @@ -12,8 +9,11 @@ impl X for () { } impl Trait for dyn X {} +//~^ ERROR the trait `X` cannot be made into an object pub fn main() { // Check that this does not segfault. <dyn X as X>::foo(&()); + //~^ ERROR the trait `X` cannot be made into an object + //~| ERROR the trait `X` cannot be made into an object } diff --git a/tests/ui/issues/issue-50781.stderr b/tests/ui/issues/issue-50781.stderr index beaea1e634c..6b0b42ca53a 100644 --- a/tests/ui/issues/issue-50781.stderr +++ b/tests/ui/issues/issue-50781.stderr @@ -1,24 +1,52 @@ -error: the trait `X` cannot be made into an object - --> $DIR/issue-50781.rs:6:8 +error[E0038]: the trait `X` cannot be made into an object + --> $DIR/issue-50781.rs:11:16 | +LL | impl Trait for dyn X {} + | ^^^^^ `X` 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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/issue-50781.rs:4:8 + | +LL | trait X { + | - this trait cannot be made into an object... LL | fn foo(&self) where Self: Trait; - | ^^^ + | ^^^ ...because method `foo` references the `Self` type in its `where` clause + = help: consider moving `foo` to another trait + = help: only type `()` implements the trait, consider using it directly instead + +error[E0038]: the trait `X` cannot be made into an object + --> $DIR/issue-50781.rs:16:23 + | +LL | <dyn X as X>::foo(&()); + | ^^^ `X` cannot be made into an object | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #51443 <https://github.com/rust-lang/rust/issues/51443> 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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/issue-50781.rs:6:8 + --> $DIR/issue-50781.rs:4:8 | LL | trait X { | - this trait cannot be made into an object... LL | fn foo(&self) where Self: Trait; | ^^^ ...because method `foo` references the `Self` type in its `where` clause = help: consider moving `foo` to another trait -note: the lint level is defined here - --> $DIR/issue-50781.rs:1:9 + = help: only type `()` implements the trait, consider using it directly instead + = note: required for the cast from `&()` to `&dyn X` + +error[E0038]: the trait `X` cannot be made into an object + --> $DIR/issue-50781.rs:16:6 + | +LL | <dyn X as X>::foo(&()); + | ^^^^^ `X` cannot be made into an object | -LL | #![deny(where_clauses_object_safety)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/issue-50781.rs:4:8 + | +LL | trait X { + | - this trait cannot be made into an object... +LL | fn foo(&self) where Self: Trait; + | ^^^ ...because method `foo` references the `Self` type in its `where` clause + = help: consider moving `foo` to another trait + = help: only type `()` implements the trait, consider using it directly instead -error: aborting due to 1 previous error +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/issues/issue-53498.rs b/tests/ui/issues/issue-53498.rs deleted file mode 100644 index 9e0437c46f4..00000000000 --- a/tests/ui/issues/issue-53498.rs +++ /dev/null @@ -1,17 +0,0 @@ -pub mod test { - pub struct A; - pub struct B; - pub struct Foo<T>(T); - - impl Foo<A> { - fn foo() {} - } - - impl Foo<B> { - fn foo() {} - } -} - -fn main() { - test::Foo::<test::B>::foo(); //~ ERROR associated function `foo` is private -} diff --git a/tests/ui/issues/issue-5708.rs b/tests/ui/issues/issue-5708.rs index ce9ef78ffcd..89ea9fbdcd8 100644 --- a/tests/ui/issues/issue-5708.rs +++ b/tests/ui/issues/issue-5708.rs @@ -44,6 +44,7 @@ pub trait MyTrait<T> { fn dummy(&self, t: T) -> T { panic!() } } +#[allow(dead_code)] pub struct MyContainer<'a, T:'a> { foos: Vec<&'a (dyn MyTrait<T>+'a)> , } diff --git a/tests/ui/layout/issue-84108.rs b/tests/ui/layout/issue-84108.rs index 425da65b990..974d5310f6b 100644 --- a/tests/ui/layout/issue-84108.rs +++ b/tests/ui/layout/issue-84108.rs @@ -8,6 +8,9 @@ static FOO: (dyn AsRef<OsStr>, u8) = ("hello", 42); const BAR: (&Path, [u8], usize) = ("hello", [], 42); //~^ ERROR cannot find type `Path` in this scope +//~| ERROR the size for values of type `[u8]` cannot be known at compilation time +//~| ERROR the size for values of type `[u8]` cannot be known at compilation time +//~| ERROR mismatched types static BAZ: ([u8], usize) = ([], 0); //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time diff --git a/tests/ui/layout/issue-84108.stderr b/tests/ui/layout/issue-84108.stderr index 6c168cc5fa8..8ddce285e23 100644 --- a/tests/ui/layout/issue-84108.stderr +++ b/tests/ui/layout/issue-84108.stderr @@ -21,7 +21,35 @@ LL + use std::path::Path; | error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/issue-84108.rs:12:13 + --> $DIR/issue-84108.rs:9:12 + | +LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42); + | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: only the last element of a tuple may have a dynamically sized type + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/issue-84108.rs:9:12 + | +LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42); + | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: only the last element of a tuple may have a dynamically sized type + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0308]: mismatched types + --> $DIR/issue-84108.rs:9:45 + | +LL | const BAR: (&Path, [u8], usize) = ("hello", [], 42); + | ^^ expected `[u8]`, found `[_; 0]` + | + = note: expected slice `[u8]` + found array `[_; 0]` + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/issue-84108.rs:15:13 | LL | static BAZ: ([u8], usize) = ([], 0); | ^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -30,7 +58,7 @@ LL | static BAZ: ([u8], usize) = ([], 0); = note: only the last element of a tuple may have a dynamically sized type error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/issue-84108.rs:12:13 + --> $DIR/issue-84108.rs:15:13 | LL | static BAZ: ([u8], usize) = ([], 0); | ^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -40,7 +68,7 @@ LL | static BAZ: ([u8], usize) = ([], 0); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0308]: mismatched types - --> $DIR/issue-84108.rs:12:30 + --> $DIR/issue-84108.rs:15:30 | LL | static BAZ: ([u8], usize) = ([], 0); | ^^ expected `[u8]`, found `[_; 0]` @@ -48,7 +76,7 @@ LL | static BAZ: ([u8], usize) = ([], 0); = note: expected slice `[u8]` found array `[_; 0]` -error: aborting due to 5 previous errors +error: aborting due to 8 previous errors Some errors have detailed explanations: E0277, E0308, E0412. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/lifetimes/issue-69314.fixed b/tests/ui/lifetimes/issue-69314.fixed index 285d192b44c..ee1675724fb 100644 --- a/tests/ui/lifetimes/issue-69314.fixed +++ b/tests/ui/lifetimes/issue-69314.fixed @@ -11,7 +11,7 @@ impl A { } async fn f() { let mut buf = [0; 512]; - let m2 = &buf[..]; //~ ERROR `buf` does not live long enough + let m2 = &buf[..]; let m = Self::g(m2).await; Self::f2(m).await; } diff --git a/tests/ui/lifetimes/issue-69314.rs b/tests/ui/lifetimes/issue-69314.rs index 345f7785060..f9e5196b2c7 100644 --- a/tests/ui/lifetimes/issue-69314.rs +++ b/tests/ui/lifetimes/issue-69314.rs @@ -11,7 +11,7 @@ impl A { } async fn f() { let mut buf = [0; 512]; - let m2 = &buf[..]; //~ ERROR `buf` does not live long enough + let m2 = &buf[..]; let m = Self::g(m2).await; Self::f2(m).await; } diff --git a/tests/ui/lifetimes/issue-69314.stderr b/tests/ui/lifetimes/issue-69314.stderr index 3879f35505c..67da54e8dcd 100644 --- a/tests/ui/lifetimes/issue-69314.stderr +++ b/tests/ui/lifetimes/issue-69314.stderr @@ -9,20 +9,6 @@ help: indicate the anonymous lifetime LL | async fn f2(m: Msg<'_>) {} | ++++ -error[E0597]: `buf` does not live long enough - --> $DIR/issue-69314.rs:14:19 - | -LL | let mut buf = [0; 512]; - | ------- binding `buf` declared here -LL | let m2 = &buf[..]; - | ^^^ borrowed value does not live long enough -LL | let m = Self::g(m2).await; - | ----------- argument requires that `buf` is borrowed for `'static` -LL | Self::f2(m).await; -LL | } - | - `buf` dropped here while still borrowed - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0597, E0726. -For more information about an error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0726`. diff --git a/tests/ui/lifetimes/no_lending_iterators.rs b/tests/ui/lifetimes/no_lending_iterators.rs new file mode 100644 index 00000000000..21395475fb3 --- /dev/null +++ b/tests/ui/lifetimes/no_lending_iterators.rs @@ -0,0 +1,35 @@ +struct Data(String); + +impl Iterator for Data { + type Item = &str; + //~^ ERROR 4:17: 4:18: associated type `Iterator::Item` is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + + fn next(&mut self) -> Option<Self::Item> { + Some(&self.0) + } +} + +trait Bar { + type Item; + fn poke(&mut self, item: Self::Item); +} + +impl Bar for usize { + type Item = &usize; + //~^ ERROR 18:17: 18:18: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + + fn poke(&mut self, item: Self::Item) { + self += *item; + } +} + +impl Bar for isize { + type Item<'a> = &'a isize; + //~^ ERROR 27:14: 27:18: lifetime parameters or bounds on type `Item` do not match the trait declaration [E0195] + + fn poke(&mut self, item: Self::Item) { + self += *item; + } +} + +fn main() {} diff --git a/tests/ui/lifetimes/no_lending_iterators.stderr b/tests/ui/lifetimes/no_lending_iterators.stderr new file mode 100644 index 00000000000..c3784770d79 --- /dev/null +++ b/tests/ui/lifetimes/no_lending_iterators.stderr @@ -0,0 +1,30 @@ +error: associated type `Iterator::Item` is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + --> $DIR/no_lending_iterators.rs:4:17 + | +LL | type Item = &str; + | ^ + | +note: you can't create an `Iterator` that borrows each `Item` from itself, but you can instead create a new type that borrows your existing type and implement `Iterator` for that new type. + --> $DIR/no_lending_iterators.rs:3:19 + | +LL | impl Iterator for Data { + | ^^^^ + +error: in the trait associated type is declared without lifetime parameters, so using a borrowed type for them requires that lifetime to come from the implemented type + --> $DIR/no_lending_iterators.rs:18:17 + | +LL | type Item = &usize; + | ^ this lifetime must come from the implemented type + +error[E0195]: lifetime parameters or bounds on type `Item` do not match the trait declaration + --> $DIR/no_lending_iterators.rs:27:14 + | +LL | type Item; + | - lifetimes in impl do not match this type in trait +... +LL | type Item<'a> = &'a isize; + | ^^^^ lifetimes do not match type in trait + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0195`. diff --git a/tests/ui/lifetimes/noisy-follow-up-erro.rs b/tests/ui/lifetimes/noisy-follow-up-erro.rs new file mode 100644 index 00000000000..47a87068d8f --- /dev/null +++ b/tests/ui/lifetimes/noisy-follow-up-erro.rs @@ -0,0 +1,23 @@ +struct Foo<'c, 'd>(&'c (), &'d ()); + +impl<'c, 'd> Foo<'c, 'd> { + fn acc(&mut self, _bar: &Bar) -> &'d () { + todo!() + } +} + +struct Bar; + +impl<'a> Bar { + fn boom(&self, foo: &mut Foo<'_, '_, 'a>) -> Result<(), &'a ()> { + //~^ ERROR: struct takes 2 lifetime arguments but 3 lifetime arguments were supplied + self.bar().map_err(|()| foo.acc(self))?; + //~^ ERROR: explicit lifetime required in the type of `foo` + Ok(()) + } + fn bar(&self) -> Result<(), &'a ()> { + todo!() + } +} + +fn main() {} diff --git a/tests/ui/lifetimes/noisy-follow-up-erro.stderr b/tests/ui/lifetimes/noisy-follow-up-erro.stderr new file mode 100644 index 00000000000..f549009a87c --- /dev/null +++ b/tests/ui/lifetimes/noisy-follow-up-erro.stderr @@ -0,0 +1,27 @@ +error[E0107]: struct takes 2 lifetime arguments but 3 lifetime arguments were supplied + --> $DIR/noisy-follow-up-erro.rs:12:30 + | +LL | fn boom(&self, foo: &mut Foo<'_, '_, 'a>) -> Result<(), &'a ()> { + | ^^^ -- help: remove this lifetime argument + | | + | expected 2 lifetime arguments + | +note: struct defined here, with 2 lifetime parameters: `'c`, `'d` + --> $DIR/noisy-follow-up-erro.rs:1:8 + | +LL | struct Foo<'c, 'd>(&'c (), &'d ()); + | ^^^ -- -- + +error[E0621]: explicit lifetime required in the type of `foo` + --> $DIR/noisy-follow-up-erro.rs:14:9 + | +LL | fn boom(&self, foo: &mut Foo<'_, '_, 'a>) -> Result<(), &'a ()> { + | -------------------- help: add explicit lifetime `'a` to the type of `foo`: `&mut Foo<'_, 'a>` +LL | +LL | self.bar().map_err(|()| foo.acc(self))?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0107, E0621. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/lifetimes/unusual-rib-combinations.rs b/tests/ui/lifetimes/unusual-rib-combinations.rs index 3bc87b9d480..0708a00d371 100644 --- a/tests/ui/lifetimes/unusual-rib-combinations.rs +++ b/tests/ui/lifetimes/unusual-rib-combinations.rs @@ -2,9 +2,8 @@ struct S<'a>(&'a u8); fn foo() {} // Paren generic args in AnonConst -fn a() -> [u8; foo::()] { -//~^ ERROR parenthesized type parameters may only be used with a `Fn` trait -//~| ERROR mismatched types +fn a() -> [u8; foo()] { + //~^ ERROR mismatched types panic!() } @@ -26,5 +25,6 @@ fn d<const C: S>() {} trait Foo<'a> {} struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>; //~^ ERROR the type of const parameters must not depend on other generic parameters +//~| ERROR `&dyn for<'a> Foo<'a>` is forbidden as the type of a const generic parameter fn main() {} diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr index 2857fc72ea1..70f06b4be60 100644 --- a/tests/ui/lifetimes/unusual-rib-combinations.stderr +++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr @@ -1,11 +1,11 @@ error[E0106]: missing lifetime specifier - --> $DIR/unusual-rib-combinations.rs:22:15 + --> $DIR/unusual-rib-combinations.rs:21:15 | LL | fn d<const C: S>() {} | ^ expected named lifetime parameter error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/unusual-rib-combinations.rs:27:22 + --> $DIR/unusual-rib-combinations.rs:26:22 | LL | struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>; | ^^ the type must not depend on the parameter `'a` @@ -13,25 +13,19 @@ LL | struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>; = note: lifetime parameters may not be used in the type of const parameters error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/unusual-rib-combinations.rs:5:16 - | -LL | fn a() -> [u8; foo::()] { - | ^^^^^^^ only `Fn` traits may use parentheses - -error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/unusual-rib-combinations.rs:12:15 + --> $DIR/unusual-rib-combinations.rs:11:15 | LL | fn b<const C: u8()>() {} | ^^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/unusual-rib-combinations.rs:16:10 + --> $DIR/unusual-rib-combinations.rs:15:10 | LL | fn c<T = u8()>() {} | ^^^^ only `Fn` traits may use parentheses error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/unusual-rib-combinations.rs:16:6 + --> $DIR/unusual-rib-combinations.rs:15:6 | LL | fn c<T = u8()>() {} | ^^^^^^^^ @@ -43,14 +37,11 @@ LL | fn c<T = u8()>() {} error[E0308]: mismatched types --> $DIR/unusual-rib-combinations.rs:5:16 | -LL | fn a() -> [u8; foo::()] { - | ^^^^^^^ expected `usize`, found fn item - | - = note: expected type `usize` - found fn item `fn() {foo}` +LL | fn a() -> [u8; foo()] { + | ^^^^^ expected `usize`, found `()` error: `S<'_>` is forbidden as the type of a const generic parameter - --> $DIR/unusual-rib-combinations.rs:22:15 + --> $DIR/unusual-rib-combinations.rs:21:15 | LL | fn d<const C: S>() {} | ^ @@ -61,6 +52,18 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more LL + #![feature(adt_const_params)] | +error: `&dyn for<'a> Foo<'a>` is forbidden as the type of a const generic parameter + --> $DIR/unusual-rib-combinations.rs:26:21 + | +LL | struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` +help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types + | +LL + #![feature(adt_const_params)] + | + error: aborting due to 8 previous errors Some errors have detailed explanations: E0106, E0214, E0308, E0770. diff --git a/tests/ui/linkage-attr/linkage-attr-mutable-static.rs b/tests/ui/linkage-attr/linkage-attr-mutable-static.rs index a7109c6d930..ed11947f59e 100644 --- a/tests/ui/linkage-attr/linkage-attr-mutable-static.rs +++ b/tests/ui/linkage-attr/linkage-attr-mutable-static.rs @@ -4,12 +4,21 @@ #![feature(linkage)] fn main() { + #[rustfmt::skip] extern "C" { - #[linkage = "weak"] //~ ERROR mutable statics are not allowed with `#[linkage]` - static mut ABC: *const u8; + #[linkage = "extern_weak"] //~ ERROR extern mutable statics are not allowed with `#[linkage]` + static mut EXTERN_WEAK: *const u8; } unsafe { - assert_eq!(ABC as usize, 0); + assert_eq!(EXTERN_WEAK as usize, 0); + } + + // static mut is fine here as this is a definition rather than declaration. + #[linkage = "weak"] + static mut WEAK_DEF: u8 = 42; + + unsafe { + assert_eq!(WEAK_DEF, 0); } } diff --git a/tests/ui/linkage-attr/linkage-attr-mutable-static.stderr b/tests/ui/linkage-attr/linkage-attr-mutable-static.stderr index 4db41b62393..ad999769047 100644 --- a/tests/ui/linkage-attr/linkage-attr-mutable-static.stderr +++ b/tests/ui/linkage-attr/linkage-attr-mutable-static.stderr @@ -1,10 +1,10 @@ -error: mutable statics are not allowed with `#[linkage]` - --> $DIR/linkage-attr-mutable-static.rs:8:9 +error: extern mutable statics are not allowed with `#[linkage]` + --> $DIR/linkage-attr-mutable-static.rs:9:9 | -LL | #[linkage = "weak"] - | ^^^^^^^^^^^^^^^^^^^ +LL | #[linkage = "extern_weak"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: making the static mutable would allow changing which symbol the static references rather than make the target of the symbol mutable + = note: marking the extern static mutable would allow changing which symbol the static references rather than make the target of the symbol mutable error: aborting due to 1 previous error diff --git a/tests/ui/lint/dead-code/lint-dead-code-1.rs b/tests/ui/lint/dead-code/lint-dead-code-1.rs index ddcafedf7bc..3386dfa4747 100644 --- a/tests/ui/lint/dead-code/lint-dead-code-1.rs +++ b/tests/ui/lint/dead-code/lint-dead-code-1.rs @@ -46,11 +46,10 @@ struct SemiUsedStruct; impl SemiUsedStruct { fn la_la_la() {} } -struct StructUsedAsField; +struct StructUsedAsField; //~ ERROR struct `StructUsedAsField` is never constructed pub struct StructUsedInEnum; struct StructUsedInGeneric; -pub struct PubStruct2 { - #[allow(dead_code)] +pub struct PubStruct2 { //~ ERROR struct `PubStruct2` is never constructed struct_used_as_field: *const StructUsedAsField } diff --git a/tests/ui/lint/dead-code/lint-dead-code-1.stderr b/tests/ui/lint/dead-code/lint-dead-code-1.stderr index eb728b5b930..b0163df8855 100644 --- a/tests/ui/lint/dead-code/lint-dead-code-1.stderr +++ b/tests/ui/lint/dead-code/lint-dead-code-1.stderr @@ -22,14 +22,26 @@ error: struct `PrivStruct` is never constructed LL | struct PrivStruct; | ^^^^^^^^^^ +error: struct `StructUsedAsField` is never constructed + --> $DIR/lint-dead-code-1.rs:49:8 + | +LL | struct StructUsedAsField; + | ^^^^^^^^^^^^^^^^^ + +error: struct `PubStruct2` is never constructed + --> $DIR/lint-dead-code-1.rs:52:12 + | +LL | pub struct PubStruct2 { + | ^^^^^^^^^^ + error: enum `priv_enum` is never used - --> $DIR/lint-dead-code-1.rs:64:6 + --> $DIR/lint-dead-code-1.rs:63:6 | LL | enum priv_enum { foo2, bar2 } | ^^^^^^^^^ error: variant `bar3` is never constructed - --> $DIR/lint-dead-code-1.rs:67:5 + --> $DIR/lint-dead-code-1.rs:66:5 | LL | enum used_enum { | --------- variant in this enum @@ -38,25 +50,25 @@ LL | bar3 | ^^^^ error: function `priv_fn` is never used - --> $DIR/lint-dead-code-1.rs:88:4 + --> $DIR/lint-dead-code-1.rs:87:4 | LL | fn priv_fn() { | ^^^^^^^ error: function `foo` is never used - --> $DIR/lint-dead-code-1.rs:93:4 + --> $DIR/lint-dead-code-1.rs:92:4 | LL | fn foo() { | ^^^ error: function `bar` is never used - --> $DIR/lint-dead-code-1.rs:98:4 + --> $DIR/lint-dead-code-1.rs:97:4 | LL | fn bar() { | ^^^ error: function `baz` is never used - --> $DIR/lint-dead-code-1.rs:102:4 + --> $DIR/lint-dead-code-1.rs:101:4 | LL | fn baz() -> impl Copy { | ^^^ @@ -67,5 +79,5 @@ error: struct `Bar` is never constructed LL | pub struct Bar; | ^^^ -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/lint/dead-code/unused-assoc-const.rs b/tests/ui/lint/dead-code/unused-assoc-const.rs new file mode 100644 index 00000000000..36e8315ad36 --- /dev/null +++ b/tests/ui/lint/dead-code/unused-assoc-const.rs @@ -0,0 +1,20 @@ +#![deny(dead_code)] + +trait Trait { + const UNUSED_CONST: i32; //~ ERROR associated constant `UNUSED_CONST` is never used + const USED_CONST: i32; + + fn foo(&self) {} +} + +pub struct T(()); + +impl Trait for T { + const UNUSED_CONST: i32 = 0; + const USED_CONST: i32 = 1; +} + +fn main() { + T(()).foo(); + T::USED_CONST; +} diff --git a/tests/ui/lint/dead-code/unused-assoc-const.stderr b/tests/ui/lint/dead-code/unused-assoc-const.stderr new file mode 100644 index 00000000000..78296d70663 --- /dev/null +++ b/tests/ui/lint/dead-code/unused-assoc-const.stderr @@ -0,0 +1,16 @@ +error: associated constant `UNUSED_CONST` is never used + --> $DIR/unused-assoc-const.rs:4:11 + | +LL | trait Trait { + | ----- associated constant in this trait +LL | const UNUSED_CONST: i32; + | ^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/unused-assoc-const.rs:1:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/dead-code/unused-pub-struct.rs b/tests/ui/lint/dead-code/unused-pub-struct.rs new file mode 100644 index 00000000000..aaf4dd612de --- /dev/null +++ b/tests/ui/lint/dead-code/unused-pub-struct.rs @@ -0,0 +1,48 @@ +#![deny(dead_code)] + +pub struct NotLint1(()); +pub struct NotLint2(std::marker::PhantomData<i32>); + +pub struct NeverConstructed(i32); //~ ERROR struct `NeverConstructed` is never constructed + +impl NeverConstructed { + pub fn not_construct_self(&self) {} +} + +impl Clone for NeverConstructed { + fn clone(&self) -> NeverConstructed { + NeverConstructed(0) + } +} + +pub trait Trait { + fn not_construct_self(&self); +} + +impl Trait for NeverConstructed { + fn not_construct_self(&self) { + self.0; + } +} + +pub struct Constructed(i32); + +impl Constructed { + pub fn construct_self() -> Self { + Constructed(0) + } +} + +impl Clone for Constructed { + fn clone(&self) -> Constructed { + Constructed(0) + } +} + +impl Trait for Constructed { + fn not_construct_self(&self) { + self.0; + } +} + +fn main() {} diff --git a/tests/ui/lint/dead-code/unused-pub-struct.stderr b/tests/ui/lint/dead-code/unused-pub-struct.stderr new file mode 100644 index 00000000000..3667ddb97bd --- /dev/null +++ b/tests/ui/lint/dead-code/unused-pub-struct.stderr @@ -0,0 +1,14 @@ +error: struct `NeverConstructed` is never constructed + --> $DIR/unused-pub-struct.rs:6:12 + | +LL | pub struct NeverConstructed(i32); + | ^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/unused-pub-struct.rs:1:9 + | +LL | #![deny(dead_code)] + | ^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/lint/non-local-defs/consts.stderr b/tests/ui/lint/non-local-defs/consts.stderr index 48bdaa60823..2756ea40138 100644 --- a/tests/ui/lint/non-local-defs/consts.stderr +++ b/tests/ui/lint/non-local-defs/consts.stderr @@ -67,13 +67,18 @@ LL | impl Test { warning: non-local `impl` definition, `impl` blocks should be written at the same level as their item --> $DIR/consts.rs:50:9 | -LL | fn main() { - | --------- move the `impl` block outside of this function `main` -... -LL | impl Test { - | ^^^^^---- - | | - | `Test` is not local +LL | const { + | ___________- +LL | | impl Test { + | | ^^^^^---- + | | | + | | `Test` is not local +LL | | +LL | | fn hoo() {} +... | +LL | | 1 +LL | | }; + | |_____- move the `impl` block outside of this inline constant `<unnameable>` and up 2 bodies | = note: methods and associated constants are still usable outside the current expression, only `impl Local` and `impl dyn Local` can ever be private, and only if the type is nested in the same item as the `impl` = note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363> diff --git a/tests/ui/lint/unreachable_pub.rs b/tests/ui/lint/unreachable_pub.rs index 22c091e112b..f21f6640342 100644 --- a/tests/ui/lint/unreachable_pub.rs +++ b/tests/ui/lint/unreachable_pub.rs @@ -9,12 +9,16 @@ mod private_mod { pub use std::env::{Args}; // braced-use has different item spans than unbraced //~^ WARNING unreachable_pub + // we lint on struct definition pub struct Hydrogen { //~ WARNING unreachable_pub - // `pub` struct fields, too - pub neutrons: usize, //~ WARNING unreachable_pub - // (... but not more-restricted fields) + // but not on fields, even if they are `pub` as putting `pub(crate)` + // it would clutter the source code for little value + pub neutrons: usize, pub(crate) electrons: usize } + pub(crate) struct Calcium { + pub neutrons: usize, + } impl Hydrogen { // impls, too pub fn count_neutrons(&self) -> usize { self.neutrons } //~ WARNING unreachable_pub diff --git a/tests/ui/lint/unreachable_pub.stderr b/tests/ui/lint/unreachable_pub.stderr index 762834b97b9..705a537a3f1 100644 --- a/tests/ui/lint/unreachable_pub.stderr +++ b/tests/ui/lint/unreachable_pub.stderr @@ -24,7 +24,7 @@ LL | pub use std::env::{Args}; // braced-use has different item spans than u = help: or consider exporting it for use by other crates warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:12:5 + --> $DIR/unreachable_pub.rs:13:5 | LL | pub struct Hydrogen { | ---^^^^^^^^^^^^^^^^ @@ -33,16 +33,8 @@ LL | pub struct Hydrogen { | = help: or consider exporting it for use by other crates -warning: unreachable `pub` field - --> $DIR/unreachable_pub.rs:14:9 - | -LL | pub neutrons: usize, - | ---^^^^^^^^^^^^^^^^ - | | - | help: consider restricting its visibility: `pub(crate)` - warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:20:9 + --> $DIR/unreachable_pub.rs:24:9 | LL | pub fn count_neutrons(&self) -> usize { self.neutrons } | ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,7 +42,7 @@ LL | pub fn count_neutrons(&self) -> usize { self.neutrons } | help: consider restricting its visibility: `pub(crate)` warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:29:5 + --> $DIR/unreachable_pub.rs:33:5 | LL | pub enum Helium {} | ---^^^^^^^^^^^^ @@ -60,7 +52,7 @@ LL | pub enum Helium {} = help: or consider exporting it for use by other crates warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:30:5 + --> $DIR/unreachable_pub.rs:34:5 | LL | pub union Lithium { c1: usize, c2: u8 } | ---^^^^^^^^^^^^^^ @@ -70,7 +62,7 @@ LL | pub union Lithium { c1: usize, c2: u8 } = help: or consider exporting it for use by other crates warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:31:5 + --> $DIR/unreachable_pub.rs:35:5 | LL | pub fn beryllium() {} | ---^^^^^^^^^^^^^^^ @@ -80,7 +72,7 @@ LL | pub fn beryllium() {} = help: or consider exporting it for use by other crates warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:32:5 + --> $DIR/unreachable_pub.rs:36:5 | LL | pub trait Boron {} | ---^^^^^^^^^^^^ @@ -90,7 +82,7 @@ LL | pub trait Boron {} = help: or consider exporting it for use by other crates warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:33:5 + --> $DIR/unreachable_pub.rs:37:5 | LL | pub const CARBON: usize = 1; | ---^^^^^^^^^^^^^^^^^^^^ @@ -100,7 +92,7 @@ LL | pub const CARBON: usize = 1; = help: or consider exporting it for use by other crates warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:34:5 + --> $DIR/unreachable_pub.rs:38:5 | LL | pub static NITROGEN: usize = 2; | ---^^^^^^^^^^^^^^^^^^^^^^^ @@ -110,7 +102,7 @@ LL | pub static NITROGEN: usize = 2; = help: or consider exporting it for use by other crates warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:35:5 + --> $DIR/unreachable_pub.rs:39:5 | LL | pub type Oxygen = bool; | ---^^^^^^^^^^^^ @@ -120,7 +112,7 @@ LL | pub type Oxygen = bool; = help: or consider exporting it for use by other crates warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:38:47 + --> $DIR/unreachable_pub.rs:42:47 | LL | ($visibility: vis, $name: ident) => { $visibility struct $name {} } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -135,7 +127,7 @@ LL | define_empty_struct_with_visibility!(pub, Fluorine); = note: this warning originates in the macro `define_empty_struct_with_visibility` (in Nightly builds, run with -Z macro-backtrace for more info) warning: unreachable `pub` item - --> $DIR/unreachable_pub.rs:44:9 + --> $DIR/unreachable_pub.rs:48:9 | LL | pub fn catalyze() -> bool; | ---^^^^^^^^^^^^^^^^^^^^^^ @@ -144,5 +136,5 @@ LL | pub fn catalyze() -> bool; | = help: or consider exporting it for use by other crates -warning: 14 warnings emitted +warning: 13 warnings emitted diff --git a/tests/ui/lint/unused/unused-doc-comments-edge-cases.rs b/tests/ui/lint/unused/unused-doc-comments-edge-cases.rs index 0f9eac93930..ba32fb566e8 100644 --- a/tests/ui/lint/unused/unused-doc-comments-edge-cases.rs +++ b/tests/ui/lint/unused/unused-doc-comments-edge-cases.rs @@ -20,10 +20,10 @@ fn doc_comment_between_if_else(num: u8) -> bool { } fn doc_comment_on_expr(num: u8) -> bool { - (/// useless doc comment + /// useless doc comment //~^ ERROR: attributes on expressions are experimental //~| ERROR: unused doc comment - num) == 3 + num == 3 } fn doc_comment_on_expr_field() -> bool { diff --git a/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr b/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr index 1ff5c8d8825..c0741174554 100644 --- a/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr +++ b/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr @@ -5,10 +5,10 @@ LL | else { | ^^^^ expected expression error[E0658]: attributes on expressions are experimental - --> $DIR/unused-doc-comments-edge-cases.rs:23:6 + --> $DIR/unused-doc-comments-edge-cases.rs:23:5 | -LL | (/// useless doc comment - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | /// useless doc comment + | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable @@ -32,12 +32,12 @@ LL | #![deny(unused_doc_comments)] | ^^^^^^^^^^^^^^^^^^^ error: unused doc comment - --> $DIR/unused-doc-comments-edge-cases.rs:23:6 + --> $DIR/unused-doc-comments-edge-cases.rs:23:5 | -LL | (/// useless doc comment - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | /// useless doc comment + | ^^^^^^^^^^^^^^^^^^^^^^^ ... -LL | num) == 3 +LL | num == 3 | --- rustdoc does not generate documentation for expressions | = help: use `//` for a plain comment diff --git a/tests/ui/macros/expand-full-no-resolution.stderr b/tests/ui/macros/expand-full-no-resolution.stderr index 2537a5032a9..df6f20332bf 100644 --- a/tests/ui/macros/expand-full-no-resolution.stderr +++ b/tests/ui/macros/expand-full-no-resolution.stderr @@ -7,7 +7,7 @@ LL | macro_rules! _a { LL | format_args!(a!()); | ^ | -help: a macro with a similar name exists, consider renaming `_a` into `a` +help: the leading underscore in `_a` marks it as unused, consider renaming it to `a` | LL | macro_rules! a { | ~ @@ -21,7 +21,7 @@ LL | macro_rules! _a { LL | env!(a!()); | ^ | -help: a macro with a similar name exists, consider renaming `_a` into `a` +help: the leading underscore in `_a` marks it as unused, consider renaming it to `a` | LL | macro_rules! a { | ~ diff --git a/tests/ui/macros/issue-61053-missing-repetition.rs b/tests/ui/macros/issue-61053-missing-repetition.rs index 6b36c730b82..77c94f24171 100644 --- a/tests/ui/macros/issue-61053-missing-repetition.rs +++ b/tests/ui/macros/issue-61053-missing-repetition.rs @@ -3,7 +3,7 @@ macro_rules! foo { () => {}; ($( $i:ident = $($j:ident),+ );*) => { $( $i = $j; )* }; - //~^ ERROR variable 'j' is still repeating + //~^ ERROR variable `j` is still repeating } macro_rules! bar { @@ -12,12 +12,12 @@ macro_rules! bar { macro_rules! nested { () => {}; ($( $i:ident = $($j:ident),+ );*) => { $( $i = $j; )* }; - //~^ ERROR variable 'j' is still repeating + //~^ ERROR variable `j` is still repeating } }; ( $( $i:ident = $($j:ident),+ );* ) => { $(macro_rules! $i { - () => { $j }; //~ ERROR variable 'j' is still repeating + () => { $j }; //~ ERROR variable `j` is still repeating })* }; } diff --git a/tests/ui/macros/issue-61053-missing-repetition.stderr b/tests/ui/macros/issue-61053-missing-repetition.stderr index 738f711f04e..ba254401f17 100644 --- a/tests/ui/macros/issue-61053-missing-repetition.stderr +++ b/tests/ui/macros/issue-61053-missing-repetition.stderr @@ -1,4 +1,4 @@ -error: variable 'j' is still repeating at this depth +error: variable `j` is still repeating at this depth --> $DIR/issue-61053-missing-repetition.rs:5:52 | LL | ($( $i:ident = $($j:ident),+ );*) => { $( $i = $j; )* }; @@ -12,7 +12,7 @@ note: the lint level is defined here LL | #![deny(meta_variable_misuse)] | ^^^^^^^^^^^^^^^^^^^^ -error: variable 'j' is still repeating at this depth +error: variable `j` is still repeating at this depth --> $DIR/issue-61053-missing-repetition.rs:14:60 | LL | ($( $i:ident = $($j:ident),+ );*) => { $( $i = $j; )* }; @@ -20,7 +20,7 @@ LL | ($( $i:ident = $($j:ident),+ );*) => { $( $i = $j; )* }; | | | expected repetition -error: variable 'j' is still repeating at this depth +error: variable `j` is still repeating at this depth --> $DIR/issue-61053-missing-repetition.rs:20:21 | LL | ( $( $i:ident = $($j:ident),+ );* ) => { diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs index 9fec546ecd6..1eda5f5bb6b 100644 --- a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs +++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs @@ -35,7 +35,7 @@ macro_rules! no_curly__no_rhs_dollar__no_round { #[rustfmt::skip] // autoformatters can break a few of the error traces macro_rules! no_curly__rhs_dollar__round { ( $( $i:ident ),* ) => { count($i) }; - //~^ ERROR variable 'i' is still repeating at this depth + //~^ ERROR variable `i` is still repeating at this depth } #[rustfmt::skip] // autoformatters can break a few of the error traces diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr index e9cef5ec6cc..3fa3839bae2 100644 --- a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr +++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr @@ -208,7 +208,7 @@ error: `count` can not be placed inside the inner-most repetition LL | ( $i:ident ) => { ${ count($i) } }; | ^^^^^^^^^^^^^ -error: variable 'i' is still repeating at this depth +error: variable `i` is still repeating at this depth --> $DIR/syntax-errors.rs:37:36 | LL | ( $( $i:ident ),* ) => { count($i) }; 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 62e4f82a3ff..829b7f86e26 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 @@ -23,9 +23,6 @@ pub fn main() { if let Some(Some(&x)) = &Some(&Some(0)) { let _: u32 = x; } - if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { - let _: u32 = x; - } if let Some(&Some(&x)) = &mut Some(&Some(0)) { let _: u32 = x; } @@ -35,9 +32,6 @@ pub fn main() { if let Some(&Some(&mut ref x)) = Some(&Some(&mut 0)) { let _: &u32 = x; } - if let Some(Some(&mut x)) = &Some(Some(&mut 0)) { - let _: &u32 = x; - } if let &Some(Some(x)) = &Some(&mut Some(0)) { let _: &u32 = x; } @@ -59,13 +53,4 @@ pub fn main() { if let Some(&Some(x)) = &mut Some(Some(0)) { let _: u32 = x; } - - let &mut x = &&mut 0; - let _: &u32 = x; - - let &mut x = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0; - let _: &u32 = x; - - let &mut &mut &mut &mut x = &mut &&&&mut &&&mut &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 96b4ff77ddb..40e8293e241 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 @@ -5,26 +5,26 @@ pub fn main() { if let Some(&mut Some(&_)) = &Some(&Some(0)) { - //~^ ERROR: mismatched types + //~^ ERROR: cannot match inherited `&` with `&mut` pattern } if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { - //~^ ERROR: mismatched types + //~^ ERROR: cannot match inherited `&` with `&mut` pattern } if let Some(&Some(x)) = &mut Some(&Some(0)) { let _: &mut u32 = x; //~^ ERROR: mismatched types } if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { - //~^ ERROR: mismatched types + //~^ ERROR: cannot match inherited `&` with `&mut` pattern } if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) { - //~^ ERROR: mismatched types + //~^ ERROR: cannot match inherited `&` with `&mut` pattern } if let Some(&mut Some(x)) = &Some(Some(0)) { - //~^ ERROR: mismatched types + //~^ ERROR: cannot match inherited `&` with `&mut` pattern } if let Some(&mut Some(x)) = &Some(Some(0)) { - //~^ ERROR: mismatched types + //~^ ERROR: cannot match inherited `&` with `&mut` pattern } let &mut _ = &&0; @@ -32,4 +32,31 @@ pub fn main() { let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; //~^ ERROR: mismatched types + + if let Some(&mut Some(&_)) = &Some(&mut Some(0)) { + //~^ ERROR: cannot match inherited `&` with `&mut` pattern + } + + if let Some(Some(&mut x)) = &Some(Some(&mut 0)) { + //~^ ERROR: cannot match inherited `&` with `&mut` pattern + } + + let &mut _ = &&mut 0; + //~^ ERROR: mismatched types + + let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0; + //~^ ERROR: mismatched types + + let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0; + //~^ ERROR: mismatched types + + struct Foo(u8); + + let Foo(mut a) = &Foo(0); + //~^ ERROR: binding cannot be both mutable and by-reference + a = &42; + + let Foo(mut a) = &mut Foo(0); + //~^ ERROR: binding cannot be both mutable and by-reference + a = &mut 42; } 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 e06a645fc0d..26317e43d02 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 @@ -1,24 +1,24 @@ -error[E0308]: mismatched types +error: cannot match inherited `&` with `&mut` pattern --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:7:17 | LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { - | ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>` - | | - | expected `Option<{integer}>`, found `&mut _` + | ^^^^^ | - = note: expected enum `Option<{integer}>` - found mutable reference `&mut _` +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(&_)) = &Some(&Some(0)) { + | ~ -error[E0308]: mismatched types +error: cannot match inherited `&` with `&mut` pattern --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:10:23 | LL | if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { - | ^^^^^^ ------------------- this expression has type `&Option<&mut Option<{integer}>>` - | | - | expected integer, found `&mut _` + | ^^^^^ | - = note: expected type `{integer}` - found mutable reference `&mut _` +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(&_)) = &Some(&mut Some(0)) { + | ~ error[E0308]: mismatched types --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:14:27 @@ -31,49 +31,49 @@ LL | let _: &mut u32 = x; = note: expected mutable reference `&mut u32` found reference `&{integer}` -error[E0308]: mismatched types +error: cannot match inherited `&` with `&mut` pattern --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:17:23 | LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { - | ^^^^^^ ------------------- this expression has type `&mut Option<&Option<{integer}>>` - | | - | expected integer, found `&mut _` + | ^^^^^ | - = note: expected type `{integer}` - found mutable reference `&mut _` +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(&_)) = &mut Some(&Some(0)) { + | ~ -error[E0308]: mismatched types +error: cannot match inherited `&` with `&mut` pattern --> $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<Option<&mut Option<{integer}>>>` - | | - | expected integer, found `&mut _` + | ^^^^^ | - = note: expected type `{integer}` - found mutable reference `&mut _` +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(Some((&_)))) = &Some(Some(&mut Some(0))) { + | ~ -error[E0308]: mismatched types +error: cannot match inherited `&` with `&mut` pattern --> $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<Option<{integer}>>` - | | - | expected `Option<{integer}>`, found `&mut _` + | ^^^^^ | - = note: expected enum `Option<{integer}>` - found mutable reference `&mut _` +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(x)) = &Some(Some(0)) { + | ~ -error[E0308]: mismatched types +error: cannot match inherited `&` with `&mut` pattern --> $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<Option<{integer}>>` - | | - | expected `Option<{integer}>`, found `&mut _` + | ^^^^^ | - = note: expected enum `Option<{integer}>` - found mutable reference `&mut _` +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(x)) = &Some(Some(0)) { + | ~ error[E0308]: mismatched types --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:30:9 @@ -81,9 +81,9 @@ error[E0308]: mismatched types LL | let &mut _ = &&0; | ^^^^^^ --- this expression has type `&&{integer}` | | - | expected integer, found `&mut _` + | types differ in mutability | - = note: expected type `{integer}` + = note: expected reference `&&{integer}` found mutable reference `&mut _` error[E0308]: mismatched types @@ -92,11 +92,87 @@ error[E0308]: mismatched types LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; | ^^^^^^ ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` | | - | expected integer, found `&mut _` + | types differ in mutability | - = note: expected type `{integer}` + = note: expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` found mutable reference `&mut _` -error: aborting due to 9 previous errors +error: cannot match inherited `&` with `&mut` pattern + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:36:17 + | +LL | if let Some(&mut Some(&_)) = &Some(&mut Some(0)) { + | ^^^^^ + | +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(&_)) = &Some(&mut Some(0)) { + | ~ + +error: cannot match inherited `&` with `&mut` pattern + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:40:22 + | +LL | if let Some(Some(&mut x)) = &Some(Some(&mut 0)) { + | ^^^^^ + | +help: replace this `&mut` pattern with `&` + | +LL | if let Some(Some(&x)) = &Some(Some(&mut 0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:44:9 + | +LL | let &mut _ = &&mut 0; + | ^^^^^^ ------- this expression has type `&&mut {integer}` + | | + | types differ in mutability + | + = note: expected reference `&&mut {integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:47:9 + | +LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&mut 0; + | ^^^^^^ --------------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}` + | | + | types differ in mutability + | + = note: expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&mut {integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:50:14 + | +LL | let &mut &mut &mut &mut _ = &mut &&&&mut &&&mut &mut 0; + | ^^^^^^^^^^^^^^^^ -------------------------- this expression has type `&mut &&&&mut &&&mut &mut {integer}` + | | + | types differ in mutability + | + = note: expected reference `&&&&mut &&&mut &mut {integer}` + found mutable reference `&mut _` + +error[E0658]: binding cannot be both mutable and by-reference + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:55:13 + | +LL | let Foo(mut a) = &Foo(0); + | ^^^^ + | + = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information + = help: add `#![feature(mut_ref)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: binding cannot be both mutable and by-reference + --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:59:13 + | +LL | let Foo(mut a) = &mut Foo(0); + | ^^^^ + | + = note: see issue #123076 <https://github.com/rust-lang/rust/issues/123076> for more information + = help: add `#![feature(mut_ref)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 16 previous errors -For more information about this error, try `rustc --explain E0308`. +Some errors have detailed explanations: E0308, E0658. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/match/ref_pat_everywhere-fail.rs b/tests/ui/match/ref_pat_everywhere-fail.rs deleted file mode 100644 index d1b1c04730d..00000000000 --- a/tests/ui/match/ref_pat_everywhere-fail.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![allow(incomplete_features)] -#![feature(ref_pat_everywhere)] -pub fn main() { - if let Some(&x) = Some(0) { - //~^ ERROR: mismatched types [E0308] - let _: u32 = x; - } - if let Some(&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 deleted file mode 100644 index 25a01129f4a..00000000000 --- a/tests/ui/match/ref_pat_everywhere-fail.stderr +++ /dev/null @@ -1,38 +0,0 @@ -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.rs b/tests/ui/match/ref_pat_everywhere.rs deleted file mode 100644 index 9a79c548475..00000000000 --- a/tests/ui/match/ref_pat_everywhere.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ run-pass -#![allow(incomplete_features)] -#![feature(ref_pat_everywhere)] - -pub fn main() { - if let Some(Some(&x)) = &Some(&Some(0)) { - let _: u32 = x; - } - if let Some(&Some(x)) = &Some(Some(0)) { - let _: u32 = x; - } - if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) { - let _: u32 = x; - } - if let Some(Some(&x)) = &Some(&mut Some(0)) { - let _: u32 = x; - } - 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/mir/lint/assignment-overlap.rs b/tests/ui/mir/lint/assignment-overlap.rs index 806d09cda85..6396cccd4e8 100644 --- a/tests/ui/mir/lint/assignment-overlap.rs +++ b/tests/ui/mir/lint/assignment-overlap.rs @@ -9,11 +9,11 @@ use core::intrinsics::mir::*; #[custom_mir(dialect = "runtime", phase = "optimized")] pub fn main() { - mir!( + mir! { let a: [u8; 1024]; { a = a; Return() } - ) + } } diff --git a/tests/ui/mir/lint/call-overlap.rs b/tests/ui/mir/lint/call-overlap.rs index eb806378fe5..def78ea1e3b 100644 --- a/tests/ui/mir/lint/call-overlap.rs +++ b/tests/ui/mir/lint/call-overlap.rs @@ -9,7 +9,7 @@ use core::intrinsics::mir::*; #[custom_mir(dialect = "runtime", phase = "optimized")] pub fn main() { - mir!( + mir! { let a: [u8; 1024]; { Call(a = f(Move(a)), ReturnTo(bb1), UnwindUnreachable()) @@ -17,7 +17,7 @@ pub fn main() { bb1 = { Return() } - ) + } } pub fn f<T: Copy>(a: T) -> T { a } diff --git a/tests/ui/mir/lint/no-storage.rs b/tests/ui/mir/lint/no-storage.rs index 42dd1b963dc..a6af8646f6e 100644 --- a/tests/ui/mir/lint/no-storage.rs +++ b/tests/ui/mir/lint/no-storage.rs @@ -8,7 +8,7 @@ use core::intrinsics::mir::*; #[custom_mir(dialect = "built")] pub fn f(a: bool) { - mir!( + mir! { let b: (); { match a { true => bb1, _ => bb2 } @@ -26,5 +26,5 @@ pub fn f(a: bool) { StorageDead(b); Return() } - ) + } } diff --git a/tests/ui/mir/lint/storage-live.rs b/tests/ui/mir/lint/storage-live.rs index 5dea1cb3567..8273544b56a 100644 --- a/tests/ui/mir/lint/storage-live.rs +++ b/tests/ui/mir/lint/storage-live.rs @@ -15,14 +15,14 @@ use core::ptr::{addr_of, addr_of_mut}; #[custom_mir(dialect = "built")] fn multiple_storage() { - mir!( + mir! { let a: usize; { StorageLive(a); StorageLive(a); Return() } - ) + } } fn main() { diff --git a/tests/ui/mir/lint/storage-return.rs b/tests/ui/mir/lint/storage-return.rs index b6281d4b2a8..d51aee9518f 100644 --- a/tests/ui/mir/lint/storage-return.rs +++ b/tests/ui/mir/lint/storage-return.rs @@ -8,12 +8,12 @@ use core::intrinsics::mir::*; #[custom_mir(dialect = "built")] fn main() { - mir!( + mir! { let a: (); { StorageLive(a); RET = a; Return() } - ) + } } diff --git a/tests/ui/mir/mir_codegen_ssa.rs b/tests/ui/mir/mir_codegen_ssa.rs index bf01edcbaa8..1666b8293eb 100644 --- a/tests/ui/mir/mir_codegen_ssa.rs +++ b/tests/ui/mir/mir_codegen_ssa.rs @@ -5,7 +5,7 @@ use std::intrinsics::mir::*; #[custom_mir(dialect = "runtime", phase = "optimized")] pub fn f(a: u32) -> u32 { - mir!( + mir! { let x: u32; { // Previously code generation failed with ICE "use of .. before def ..." because the @@ -15,5 +15,5 @@ pub fn f(a: u32) -> u32 { RET = x; Return() } - ) + } } diff --git a/tests/ui/mir/ssa_call_ret.rs b/tests/ui/mir/ssa_call_ret.rs index 9b2c78c737f..baaa7326fd8 100644 --- a/tests/ui/mir/ssa_call_ret.rs +++ b/tests/ui/mir/ssa_call_ret.rs @@ -10,7 +10,7 @@ use core::intrinsics::mir::*; #[custom_mir(dialect = "runtime", phase = "optimized")] pub fn f() -> u32 { - mir!( + mir! { let a: u32; { Call(a = g(), ReturnTo(bb1), UnwindCleanup(bb2)) @@ -23,7 +23,7 @@ pub fn f() -> u32 { RET = a; UnwindResume() } - ) + } } #[inline(never)] diff --git a/tests/ui/mir/validate/critical-edge.rs b/tests/ui/mir/validate/critical-edge.rs index 0a548ae8e58..9048d08a22a 100644 --- a/tests/ui/mir/validate/critical-edge.rs +++ b/tests/ui/mir/validate/critical-edge.rs @@ -12,7 +12,7 @@ use core::intrinsics::mir::*; #[custom_mir(dialect = "runtime", phase = "optimized")] #[inline(always)] pub fn f(a: u32) -> u32 { - mir!( + mir! { { match a { 0 => bb1, @@ -27,5 +27,5 @@ pub fn f(a: u32) -> u32 { RET = 2; Return() } - ) + } } diff --git a/tests/ui/mir/validate/noncleanup-cleanup.rs b/tests/ui/mir/validate/noncleanup-cleanup.rs index 744e71e99b1..b46bb46952b 100644 --- a/tests/ui/mir/validate/noncleanup-cleanup.rs +++ b/tests/ui/mir/validate/noncleanup-cleanup.rs @@ -9,13 +9,12 @@ use core::intrinsics::mir::*; #[custom_mir(dialect = "built")] pub fn main() { - mir!( + mir! { { Call(RET = main(), ReturnTo(block), UnwindCleanup(block)) } block = { Return() } - ) - + } } diff --git a/tests/ui/mir/validate/noncleanup-resume.rs b/tests/ui/mir/validate/noncleanup-resume.rs index 5bf6b03c9e9..b2a0e92e068 100644 --- a/tests/ui/mir/validate/noncleanup-resume.rs +++ b/tests/ui/mir/validate/noncleanup-resume.rs @@ -9,9 +9,9 @@ use core::intrinsics::mir::*; #[custom_mir(dialect = "built")] pub fn main() { - mir!( + mir! { { UnwindResume() } - ) + } } diff --git a/tests/ui/mir/validate/noncleanup-terminate.rs b/tests/ui/mir/validate/noncleanup-terminate.rs index b5bf2604cce..24cf75e7d8e 100644 --- a/tests/ui/mir/validate/noncleanup-terminate.rs +++ b/tests/ui/mir/validate/noncleanup-terminate.rs @@ -9,9 +9,9 @@ use core::intrinsics::mir::*; #[custom_mir(dialect = "built")] pub fn main() { - mir!( + mir! { { UnwindTerminate(ReasonAbi) } - ) + } } diff --git a/tests/ui/object-safety/issue-106247.rs b/tests/ui/object-safety/issue-106247.rs index 78bae568161..20a451a59a1 100644 --- a/tests/ui/object-safety/issue-106247.rs +++ b/tests/ui/object-safety/issue-106247.rs @@ -1,7 +1,5 @@ //@ check-pass -#![deny(where_clauses_object_safety)] - pub trait Trait { fn method(&self) where Self: Sync; } diff --git a/tests/ui/offset-of/offset-of-dst-field.rs b/tests/ui/offset-of/offset-of-dst-field.rs index 016ebfadd14..5ae15f32357 100644 --- a/tests/ui/offset-of/offset-of-dst-field.rs +++ b/tests/ui/offset-of/offset-of-dst-field.rs @@ -49,3 +49,7 @@ fn delta() { fn generic_with_maybe_sized<T: ?Sized>() -> usize { offset_of!(Delta<T>, z) //~ ERROR the size for values of type } + +fn illformed_tuple() { + offset_of!(([u8], u8), 1); //~ ERROR the size for values of type +} diff --git a/tests/ui/offset-of/offset-of-dst-field.stderr b/tests/ui/offset-of/offset-of-dst-field.stderr index adfd16c6f2b..bcfe796897e 100644 --- a/tests/ui/offset-of/offset-of-dst-field.stderr +++ b/tests/ui/offset-of/offset-of-dst-field.stderr @@ -81,6 +81,15 @@ LL - fn generic_with_maybe_sized<T: ?Sized>() -> usize { LL + fn generic_with_maybe_sized<T>() -> usize { | -error: aborting due to 8 previous errors +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/offset-of-dst-field.rs:54:16 + | +LL | offset_of!(([u8], u8), 1); + | ^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: only the last element of a tuple may have a dynamically sized type + +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/offset-of/offset-of-slice.rs b/tests/ui/offset-of/offset-of-slice.rs new file mode 100644 index 00000000000..a0fe3198f68 --- /dev/null +++ b/tests/ui/offset-of/offset-of-slice.rs @@ -0,0 +1,26 @@ +//@run-pass +#![feature(offset_of_slice, offset_of_nested)] + +use std::mem::offset_of; + +#[repr(C)] +struct S { + a: u8, + b: (u8, u8), + c: [i32], +} + +#[repr(C)] +struct T { + x: i8, + y: S, +} + +type Tup = (i16, [i32]); + +fn main() { + assert_eq!(offset_of!(S, c), 4); + assert_eq!(offset_of!(T, y), 4); + assert_eq!(offset_of!(T, y.c), 8); + assert_eq!(offset_of!(Tup, 1), 4); +} diff --git a/tests/ui/parser/attribute/attr-binary-expr-ambigous.fixed b/tests/ui/parser/attribute/attr-binary-expr-ambigous.fixed deleted file mode 100644 index aae71ede771..00000000000 --- a/tests/ui/parser/attribute/attr-binary-expr-ambigous.fixed +++ /dev/null @@ -1,15 +0,0 @@ -//@ run-rustfix -#![feature(stmt_expr_attributes)] -#![allow(unused_assignments, unused_attributes)] - -fn main() { - let mut x = (#[deprecated] 1) + 2; //~ ERROR ambiguous - - (#[deprecated] x) = 4; //~ ERROR ambiguous - - x = (#[deprecated] 5) as i32; //~ ERROR ambiguous - - let _r = (#[deprecated] 1)..6; //~ ERROR ambiguous - - println!("{}", x); -} diff --git a/tests/ui/parser/attribute/attr-binary-expr-ambigous.rs b/tests/ui/parser/attribute/attr-binary-expr-ambigous.rs deleted file mode 100644 index 613e01d743b..00000000000 --- a/tests/ui/parser/attribute/attr-binary-expr-ambigous.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ run-rustfix -#![feature(stmt_expr_attributes)] -#![allow(unused_assignments, unused_attributes)] - -fn main() { - let mut x = #[deprecated] 1 + 2; //~ ERROR ambiguous - - #[deprecated] x = 4; //~ ERROR ambiguous - - x = #[deprecated] 5 as i32; //~ ERROR ambiguous - - let _r = #[deprecated] 1..6; //~ ERROR ambiguous - - println!("{}", x); -} diff --git a/tests/ui/parser/attribute/attr-binary-expr-ambigous.stderr b/tests/ui/parser/attribute/attr-binary-expr-ambigous.stderr deleted file mode 100644 index 0430570fd49..00000000000 --- a/tests/ui/parser/attribute/attr-binary-expr-ambigous.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error: ambiguous outer attributes - --> $DIR/attr-binary-expr-ambigous.rs:6:17 - | -LL | let mut x = #[deprecated] 1 + 2; - | ^^^^^^^^^^^^^^^^^^^ - | -help: wrap the expression in parentheses - | -LL | let mut x = (#[deprecated] 1) + 2; - | + + - -error: ambiguous outer attributes - --> $DIR/attr-binary-expr-ambigous.rs:8:5 - | -LL | #[deprecated] x = 4; - | ^^^^^^^^^^^^^^^^^^^ - | -help: wrap the expression in parentheses - | -LL | (#[deprecated] x) = 4; - | + + - -error: ambiguous outer attributes - --> $DIR/attr-binary-expr-ambigous.rs:10:9 - | -LL | x = #[deprecated] 5 as i32; - | ^^^^^^^^^^^^^^^^^^^^^^ - | -help: wrap the expression in parentheses - | -LL | x = (#[deprecated] 5) as i32; - | + + - -error: ambiguous outer attributes - --> $DIR/attr-binary-expr-ambigous.rs:12:14 - | -LL | let _r = #[deprecated] 1..6; - | ^^^^^^^^^^^^^^^^^^ - | -help: wrap the expression in parentheses - | -LL | let _r = (#[deprecated] 1)..6; - | + + - -error: aborting due to 4 previous errors - diff --git a/tests/ui/parser/duplicate-visibility.rs b/tests/ui/parser/duplicate-visibility.rs index 54955944c7d..f0ee60873da 100644 --- a/tests/ui/parser/duplicate-visibility.rs +++ b/tests/ui/parser/duplicate-visibility.rs @@ -2,8 +2,8 @@ fn main() {} extern "C" { //~ NOTE while parsing this item list starting here pub pub fn foo(); - //~^ ERROR expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `unsafe`, or `use`, found keyword `pub` - //~| NOTE expected one of 8 possible tokens + //~^ ERROR expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `safe`, `unsafe`, or `use`, found keyword `pub` + //~| NOTE expected one of 9 possible tokens //~| HELP there is already a visibility modifier, remove one //~| NOTE explicit visibility first seen here } //~ NOTE the item list ends here diff --git a/tests/ui/parser/duplicate-visibility.stderr b/tests/ui/parser/duplicate-visibility.stderr index b578b1fe26e..0d1421ee7f4 100644 --- a/tests/ui/parser/duplicate-visibility.stderr +++ b/tests/ui/parser/duplicate-visibility.stderr @@ -1,4 +1,4 @@ -error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `unsafe`, or `use`, found keyword `pub` +error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `safe`, `unsafe`, or `use`, found keyword `pub` --> $DIR/duplicate-visibility.rs:4:9 | LL | extern "C" { @@ -6,7 +6,7 @@ LL | extern "C" { LL | pub pub fn foo(); | ^^^ | | - | expected one of 8 possible tokens + | expected one of 9 possible tokens | help: there is already a visibility modifier, remove one ... LL | } diff --git a/tests/ui/parser/fn-header-semantic-fail.rs b/tests/ui/parser/fn-header-semantic-fail.rs index 6ed173b6854..5907ac05260 100644 --- a/tests/ui/parser/fn-header-semantic-fail.rs +++ b/tests/ui/parser/fn-header-semantic-fail.rs @@ -44,13 +44,14 @@ fn main() { extern "C" { async fn fe1(); //~ ERROR functions in `extern` blocks cannot have qualifiers - unsafe fn fe2(); //~ ERROR functions in `extern` blocks cannot have qualifiers + unsafe fn fe2(); //~ ERROR items in unadorned `extern` blocks cannot have safety qualifiers const fn fe3(); //~ ERROR functions in `extern` blocks cannot have qualifiers extern "C" fn fe4(); //~ ERROR functions in `extern` blocks cannot have qualifiers - const async unsafe extern "C" fn fe5(); //~ ERROR functions in `extern` blocks - //~| ERROR functions in `extern` blocks + const async unsafe extern "C" fn fe5(); + //~^ ERROR functions in `extern` blocks //~| ERROR functions in `extern` blocks //~| ERROR functions in `extern` blocks //~| ERROR functions cannot be both `const` and `async` + //~| ERROR items in unadorned `extern` blocks cannot have safety qualifiers } } diff --git a/tests/ui/parser/fn-header-semantic-fail.stderr b/tests/ui/parser/fn-header-semantic-fail.stderr index cfc54839eb7..abaa6527b0a 100644 --- a/tests/ui/parser/fn-header-semantic-fail.stderr +++ b/tests/ui/parser/fn-header-semantic-fail.stderr @@ -78,14 +78,14 @@ LL | extern "C" { LL | async fn fe1(); | ^^^^^ help: remove this qualifier -error: functions in `extern` blocks cannot have qualifiers +error: items in unadorned `extern` blocks cannot have safety qualifiers --> $DIR/fn-header-semantic-fail.rs:47:9 | LL | extern "C" { - | ---------- in this `extern` block + | ---------- help: add unsafe to this `extern` block LL | async fn fe1(); LL | unsafe fn fe2(); - | ^^^^^^ help: remove this qualifier + | ^^^^^^^^^^^^^^^^ error: functions in `extern` blocks cannot have qualifiers --> $DIR/fn-header-semantic-fail.rs:48:9 @@ -105,14 +105,14 @@ LL | extern "C" { LL | extern "C" fn fe4(); | ^^^^^^^^^^ help: remove this qualifier -error: functions in `extern` blocks cannot have qualifiers - --> $DIR/fn-header-semantic-fail.rs:50:21 +error: items in unadorned `extern` blocks cannot have safety qualifiers + --> $DIR/fn-header-semantic-fail.rs:50:9 | LL | extern "C" { - | ---------- in this `extern` block + | ---------- help: add unsafe to this `extern` block ... LL | const async unsafe extern "C" fn fe5(); - | ^^^^^^ help: remove this qualifier + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: functions in `extern` blocks cannot have qualifiers --> $DIR/fn-header-semantic-fail.rs:50:15 diff --git a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs index f6aa39df27d..1c28c0632fa 100644 --- a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs +++ b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs @@ -5,3 +5,4 @@ struct Apple((Apple, Option(Banana ? Citron))); //~| ERROR expected one of `)` or `,`, found `Citron` //~| ERROR cannot find type `Citron` in this scope [E0412] //~| ERROR parenthesized type parameters may only be used with a `Fn` trait [E0214] +//~| ERROR `Apple` has infinite size diff --git a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr index 71d2d7b7975..b0d8b03ae08 100644 --- a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr +++ b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr @@ -34,7 +34,18 @@ help: use angle brackets instead LL | struct Apple((Apple, Option<Banana ? Citron>)); | ~ ~ -error: aborting due to 4 previous errors +error[E0072]: recursive type `Apple` has infinite size + --> $DIR/issue-103748-ICE-wrong-braces.rs:3:1 + | +LL | struct Apple((Apple, Option(Banana ? Citron))); + | ^^^^^^^^^^^^ ----- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle + | +LL | struct Apple((Box<Apple>, Option(Banana ? Citron))); + | ++++ + + +error: aborting due to 5 previous errors -Some errors have detailed explanations: E0214, E0412. -For more information about an error, try `rustc --explain E0214`. +Some errors have detailed explanations: E0072, E0214, E0412. +For more information about an error, try `rustc --explain E0072`. diff --git a/tests/ui/parser/issues/issue-76437-async.rs b/tests/ui/parser/issues/issue-76437-async.rs index 497e269d634..3fafaad0277 100644 --- a/tests/ui/parser/issues/issue-76437-async.rs +++ b/tests/ui/parser/issues/issue-76437-async.rs @@ -2,6 +2,6 @@ mod t { async pub fn t() {} - //~^ ERROR expected one of `extern`, `fn`, or `unsafe`, found keyword `pub` + //~^ ERROR expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` //~| HELP visibility `pub` must come before `async` } diff --git a/tests/ui/parser/issues/issue-76437-async.stderr b/tests/ui/parser/issues/issue-76437-async.stderr index 7f2df5c8736..483599135f5 100644 --- a/tests/ui/parser/issues/issue-76437-async.stderr +++ b/tests/ui/parser/issues/issue-76437-async.stderr @@ -1,10 +1,10 @@ -error: expected one of `extern`, `fn`, or `unsafe`, found keyword `pub` +error: expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` --> $DIR/issue-76437-async.rs:4:11 | LL | async pub fn t() {} | ------^^^ | | | - | | expected one of `extern`, `fn`, or `unsafe` + | | expected one of `extern`, `fn`, `safe`, or `unsafe` | help: visibility `pub` must come before `async`: `pub async` error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-76437-const-async.rs b/tests/ui/parser/issues/issue-76437-const-async.rs index 45d53c63933..d8eb6cdecf1 100644 --- a/tests/ui/parser/issues/issue-76437-const-async.rs +++ b/tests/ui/parser/issues/issue-76437-const-async.rs @@ -2,6 +2,6 @@ mod t { const async pub fn t() {} - //~^ ERROR expected one of `extern`, `fn`, or `unsafe`, found keyword `pub` + //~^ ERROR expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` //~| HELP visibility `pub` must come before `const async` } diff --git a/tests/ui/parser/issues/issue-76437-const-async.stderr b/tests/ui/parser/issues/issue-76437-const-async.stderr index a9acccdce18..81fa8a5f557 100644 --- a/tests/ui/parser/issues/issue-76437-const-async.stderr +++ b/tests/ui/parser/issues/issue-76437-const-async.stderr @@ -1,10 +1,10 @@ -error: expected one of `extern`, `fn`, or `unsafe`, found keyword `pub` +error: expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` --> $DIR/issue-76437-const-async.rs:4:17 | LL | const async pub fn t() {} | ------------^^^ | | | - | | expected one of `extern`, `fn`, or `unsafe` + | | expected one of `extern`, `fn`, `safe`, or `unsafe` | help: visibility `pub` must come before `const async`: `pub const async` error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-76437-const.rs b/tests/ui/parser/issues/issue-76437-const.rs index c3431e3567b..dad63f137c0 100644 --- a/tests/ui/parser/issues/issue-76437-const.rs +++ b/tests/ui/parser/issues/issue-76437-const.rs @@ -2,6 +2,6 @@ mod t { const pub fn t() {} - //~^ ERROR expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub` + //~^ ERROR expected one of `async`, `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` //~| HELP visibility `pub` must come before `const` } diff --git a/tests/ui/parser/issues/issue-76437-const.stderr b/tests/ui/parser/issues/issue-76437-const.stderr index 4c36d773d60..005a27b7c24 100644 --- a/tests/ui/parser/issues/issue-76437-const.stderr +++ b/tests/ui/parser/issues/issue-76437-const.stderr @@ -1,10 +1,10 @@ -error: expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub` +error: expected one of `async`, `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` --> $DIR/issue-76437-const.rs:4:11 | LL | const pub fn t() {} | ------^^^ | | | - | | expected one of `async`, `extern`, `fn`, or `unsafe` + | | expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` | help: visibility `pub` must come before `const`: `pub const` error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-86895.rs b/tests/ui/parser/issues/issue-86895.rs index 4cd09843107..3e5dc41e2f4 100644 --- a/tests/ui/parser/issues/issue-86895.rs +++ b/tests/ui/parser/issues/issue-86895.rs @@ -1,3 +1,3 @@ const pub () {} -//~^ ERROR expected one of `async`, `extern`, `fn`, or `unsafe` +//~^ ERROR expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` pub fn main() {} diff --git a/tests/ui/parser/issues/issue-86895.stderr b/tests/ui/parser/issues/issue-86895.stderr index dcde7242d39..14183ee0a5c 100644 --- a/tests/ui/parser/issues/issue-86895.stderr +++ b/tests/ui/parser/issues/issue-86895.stderr @@ -1,8 +1,8 @@ -error: expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub` +error: expected one of `async`, `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` --> $DIR/issue-86895.rs:1:7 | LL | const pub () {} - | ^^^ expected one of `async`, `extern`, `fn`, or `unsafe` + | ^^^ expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` error: aborting due to 1 previous error diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs index 694729376ba..e6235b1e892 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs +++ b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs @@ -3,8 +3,8 @@ // Test that even when `const` is already present, the proposed fix is to remove the second `const` const async const fn test() {} -//~^ ERROR expected one of `extern`, `fn`, or `unsafe`, found keyword `const` -//~| NOTE expected one of `extern`, `fn`, or `unsafe` +//~^ ERROR expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `const` +//~| NOTE expected one of `extern`, `fn`, `safe`, or `unsafe` //~| HELP `const` already used earlier, remove this one //~| NOTE `const` first seen here //~| ERROR functions cannot be both `const` and `async` diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr index 4c55179ce23..ed2e4d81549 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr +++ b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.stderr @@ -1,10 +1,10 @@ -error: expected one of `extern`, `fn`, or `unsafe`, found keyword `const` +error: expected one of `extern`, `fn`, `safe`, or `unsafe`, found keyword `const` --> $DIR/const-async-const.rs:5:13 | LL | const async const fn test() {} | ^^^^^ | | - | expected one of `extern`, `fn`, or `unsafe` + | expected one of `extern`, `fn`, `safe`, or `unsafe` | help: `const` already used earlier, remove this one | note: `const` first seen here diff --git a/tests/ui/parser/issues/issue-87694-duplicated-pub.rs b/tests/ui/parser/issues/issue-87694-duplicated-pub.rs index e3ea61dc4ad..816c8ff2a9f 100644 --- a/tests/ui/parser/issues/issue-87694-duplicated-pub.rs +++ b/tests/ui/parser/issues/issue-87694-duplicated-pub.rs @@ -1,5 +1,5 @@ pub const pub fn test() {} -//~^ ERROR expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub` -//~| NOTE expected one of `async`, `extern`, `fn`, or `unsafe` +//~^ ERROR expected one of `async`, `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` +//~| NOTE expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` //~| HELP there is already a visibility modifier, remove one //~| NOTE explicit visibility first seen here diff --git a/tests/ui/parser/issues/issue-87694-duplicated-pub.stderr b/tests/ui/parser/issues/issue-87694-duplicated-pub.stderr index a210238652a..dd75f32f68f 100644 --- a/tests/ui/parser/issues/issue-87694-duplicated-pub.stderr +++ b/tests/ui/parser/issues/issue-87694-duplicated-pub.stderr @@ -1,10 +1,10 @@ -error: expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub` +error: expected one of `async`, `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` --> $DIR/issue-87694-duplicated-pub.rs:1:11 | LL | pub const pub fn test() {} | ^^^ | | - | expected one of `async`, `extern`, `fn`, or `unsafe` + | expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` | help: there is already a visibility modifier, remove one | note: explicit visibility first seen here diff --git a/tests/ui/parser/issues/issue-87694-misplaced-pub.rs b/tests/ui/parser/issues/issue-87694-misplaced-pub.rs index 3f824617cad..b5b0bc5b2fc 100644 --- a/tests/ui/parser/issues/issue-87694-misplaced-pub.rs +++ b/tests/ui/parser/issues/issue-87694-misplaced-pub.rs @@ -1,5 +1,5 @@ const pub fn test() {} -//~^ ERROR expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub` -//~| NOTE expected one of `async`, `extern`, `fn`, or `unsafe` +//~^ ERROR expected one of `async`, `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` +//~| NOTE expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` //~| HELP visibility `pub` must come before `const` //~| SUGGESTION pub const diff --git a/tests/ui/parser/issues/issue-87694-misplaced-pub.stderr b/tests/ui/parser/issues/issue-87694-misplaced-pub.stderr index 6f686a7e504..d35e09dceaf 100644 --- a/tests/ui/parser/issues/issue-87694-misplaced-pub.stderr +++ b/tests/ui/parser/issues/issue-87694-misplaced-pub.stderr @@ -1,10 +1,10 @@ -error: expected one of `async`, `extern`, `fn`, or `unsafe`, found keyword `pub` +error: expected one of `async`, `extern`, `fn`, `safe`, or `unsafe`, found keyword `pub` --> $DIR/issue-87694-misplaced-pub.rs:1:7 | LL | const pub fn test() {} | ------^^^ | | | - | | expected one of `async`, `extern`, `fn`, or `unsafe` + | | expected one of `async`, `extern`, `fn`, `safe`, or `unsafe` | help: visibility `pub` must come before `const`: `pub const` error: aborting due to 1 previous error diff --git a/tests/ui/parser/macro/macro-repeat.stderr b/tests/ui/parser/macro/macro-repeat.stderr index ade2bbf9b0b..ba722ab6cf9 100644 --- a/tests/ui/parser/macro/macro-repeat.stderr +++ b/tests/ui/parser/macro/macro-repeat.stderr @@ -1,10 +1,10 @@ -error: variable 'v' is still repeating at this depth +error: variable `v` is still repeating at this depth --> $DIR/macro-repeat.rs:3:9 | LL | $v | ^^ -error: variable 'v' is still repeating at this depth +error: variable `v` is still repeating at this depth --> $DIR/macro-repeat.rs:3:9 | LL | $v diff --git a/tests/ui/parser/no-const-fn-in-extern-block.rs b/tests/ui/parser/no-const-fn-in-extern-block.rs index d6c578681cc..3ad9ba006d3 100644 --- a/tests/ui/parser/no-const-fn-in-extern-block.rs +++ b/tests/ui/parser/no-const-fn-in-extern-block.rs @@ -3,7 +3,7 @@ extern "C" { //~^ ERROR functions in `extern` blocks cannot have qualifiers const unsafe fn bar(); //~^ ERROR functions in `extern` blocks cannot have qualifiers - //~| ERROR functions in `extern` blocks cannot have qualifiers + //~| ERROR items in unadorned `extern` blocks cannot have safety qualifiers } fn main() {} diff --git a/tests/ui/parser/no-const-fn-in-extern-block.stderr b/tests/ui/parser/no-const-fn-in-extern-block.stderr index 948ce669112..892024ce893 100644 --- a/tests/ui/parser/no-const-fn-in-extern-block.stderr +++ b/tests/ui/parser/no-const-fn-in-extern-block.stderr @@ -6,14 +6,14 @@ LL | extern "C" { LL | const fn foo(); | ^^^^^ help: remove this qualifier -error: functions in `extern` blocks cannot have qualifiers - --> $DIR/no-const-fn-in-extern-block.rs:4:11 +error: items in unadorned `extern` blocks cannot have safety qualifiers + --> $DIR/no-const-fn-in-extern-block.rs:4:5 | LL | extern "C" { - | ---------- in this `extern` block + | ---------- help: add unsafe to this `extern` block ... LL | const unsafe fn bar(); - | ^^^^^^ help: remove this qualifier + | ^^^^^^^^^^^^^^^^^^^^^^ error: functions in `extern` blocks cannot have qualifiers --> $DIR/no-const-fn-in-extern-block.rs:4:5 diff --git a/tests/ui/parser/recover/recover-range-pats.stderr b/tests/ui/parser/recover/recover-range-pats.stderr index e0ea8ec24dc..e29b6c1c666 100644 --- a/tests/ui/parser/recover/recover-range-pats.stderr +++ b/tests/ui/parser/recover/recover-range-pats.stderr @@ -316,9 +316,6 @@ LL | if let X.. .0 = 0 {} | | | | | expected `u8`, found floating-point number | this is of type `u8` - | - = note: expected type `u8` - found type `{float}` error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:31:12 @@ -353,9 +350,6 @@ LL | if let X..=.0 = 0 {} | | | | | expected `u8`, found floating-point number | this is of type `u8` - | - = note: expected type `u8` - found type `{float}` error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:52:12 @@ -390,9 +384,6 @@ LL | if let X... .0 = 0 {} | | | | | expected `u8`, found floating-point number | this is of type `u8` - | - = note: expected type `u8` - found type `{float}` error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:71:12 diff --git a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed index a851300a982..e9c89807fa5 100644 --- a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed +++ b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.fixed @@ -1,7 +1,8 @@ // Regression test for issues #100790 and #106439. //@ run-rustfix -pub struct Example(#[allow(dead_code)] usize) +#[allow(dead_code)] +pub struct Example(usize) where (): Sized; //~^^^ ERROR where clauses are not allowed before tuple struct bodies diff --git a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs index 10f435859f1..3bd0f51ec2c 100644 --- a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs +++ b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.rs @@ -1,10 +1,11 @@ // Regression test for issues #100790 and #106439. //@ run-rustfix +#[allow(dead_code)] pub struct Example where (): Sized, -(#[allow(dead_code)] usize); +(usize); //~^^^ ERROR where clauses are not allowed before tuple struct bodies struct _Demo diff --git a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr index ddbf237e866..77eafa6bea3 100644 --- a/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr +++ b/tests/ui/parser/recover/recover-where-clause-before-tuple-struct-body-0.stderr @@ -1,23 +1,23 @@ error: where clauses are not allowed before tuple struct bodies - --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:5:1 + --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:6:1 | LL | pub struct Example | ------- while parsing this tuple struct LL | / where LL | | (): Sized, | |______________^ unexpected where clause -LL | (#[allow(dead_code)] usize); - | --------------------------- the struct body +LL | (usize); + | ------- the struct body | help: move the body before the where clause | -LL ~ pub struct Example(#[allow(dead_code)] usize) +LL ~ pub struct Example(usize) LL | where LL ~ (): Sized; | error: where clauses are not allowed before tuple struct bodies - --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:11:1 + --> $DIR/recover-where-clause-before-tuple-struct-body-0.rs:12:1 | LL | struct _Demo | ----- while parsing this tuple struct diff --git a/tests/ui/parser/unsafe-foreign-mod-2.rs b/tests/ui/parser/unsafe-foreign-mod-2.rs index 77856fb6734..0b63a993c5b 100644 --- a/tests/ui/parser/unsafe-foreign-mod-2.rs +++ b/tests/ui/parser/unsafe-foreign-mod-2.rs @@ -1,8 +1,8 @@ extern "C" unsafe { - //~^ ERROR expected `{`, found keyword `unsafe` - //~| ERROR extern block cannot be declared unsafe + //~^ ERROR expected `{`, found keyword `unsafe` + //~| ERROR extern block cannot be declared unsafe unsafe fn foo(); - //~^ ERROR functions in `extern` blocks cannot have qualifiers + //~^ ERROR items in unadorned `extern` blocks cannot have safety qualifiers } fn main() {} diff --git a/tests/ui/parser/unsafe-foreign-mod-2.stderr b/tests/ui/parser/unsafe-foreign-mod-2.stderr index fc05184f018..e59352395ed 100644 --- a/tests/ui/parser/unsafe-foreign-mod-2.stderr +++ b/tests/ui/parser/unsafe-foreign-mod-2.stderr @@ -10,14 +10,14 @@ error: extern block cannot be declared unsafe LL | extern "C" unsafe { | ^^^^^^ -error: functions in `extern` blocks cannot have qualifiers +error: items in unadorned `extern` blocks cannot have safety qualifiers --> $DIR/unsafe-foreign-mod-2.rs:4:5 | LL | extern "C" unsafe { - | ----------------- in this `extern` block + | ----------------- help: add unsafe to this `extern` block ... LL | unsafe fn foo(); - | ^^^^^^ help: remove this qualifier + | ^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/pattern/feature-gate-mut_preserve_binding_mode_2024.rs b/tests/ui/pattern/feature-gate-mut_preserve_binding_mode_2024.rs deleted file mode 100644 index 15c542e6bf1..00000000000 --- a/tests/ui/pattern/feature-gate-mut_preserve_binding_mode_2024.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ edition: 2024 -//@ compile-flags: -Zunstable-options - -struct Foo(u8); - -fn main() { - let Foo(mut a) = &Foo(0); - a = &42; - //~^ ERROR: mismatched types - - let Foo(mut a) = &mut Foo(0); - a = &mut 42; - //~^ ERROR: mismatched types -} diff --git a/tests/ui/pattern/feature-gate-mut_preserve_binding_mode_2024.stderr b/tests/ui/pattern/feature-gate-mut_preserve_binding_mode_2024.stderr deleted file mode 100644 index 6d0a034be21..00000000000 --- a/tests/ui/pattern/feature-gate-mut_preserve_binding_mode_2024.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/feature-gate-mut_preserve_binding_mode_2024.rs:8:9 - | -LL | let Foo(mut a) = &Foo(0); - | ----- expected due to the type of this binding -LL | a = &42; - | ^^^ expected `u8`, found `&{integer}` - | -help: consider removing the borrow - | -LL - a = &42; -LL + a = 42; - | - -error[E0308]: mismatched types - --> $DIR/feature-gate-mut_preserve_binding_mode_2024.rs:12:9 - | -LL | let Foo(mut a) = &mut Foo(0); - | ----- expected due to the type of this binding -LL | a = &mut 42; - | ^^^^^^^ expected `u8`, found `&mut {integer}` - | -help: consider removing the borrow - | -LL - a = &mut 42; -LL + a = 42; - | - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/match_ergonomics_2024.fixed b/tests/ui/pattern/match_ergonomics_2024.fixed index d8dbcb217c0..1ec2b5a214b 100644 --- a/tests/ui/pattern/match_ergonomics_2024.fixed +++ b/tests/ui/pattern/match_ergonomics_2024.fixed @@ -2,7 +2,7 @@ //@ 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)] +#![feature(mut_ref, ref_pat_eat_one_layer_2024)] #![allow(incomplete_features, unused)] #![deny(rust_2024_incompatible_pat)] diff --git a/tests/ui/pattern/match_ergonomics_2024.rs b/tests/ui/pattern/match_ergonomics_2024.rs index 38dc0c8bebb..c9f992c12d4 100644 --- a/tests/ui/pattern/match_ergonomics_2024.rs +++ b/tests/ui/pattern/match_ergonomics_2024.rs @@ -2,7 +2,7 @@ //@ 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)] +#![feature(mut_ref, ref_pat_eat_one_layer_2024)] #![allow(incomplete_features, unused)] #![deny(rust_2024_incompatible_pat)] diff --git a/tests/ui/pattern/mut_preserve_binding_mode_2021.rs b/tests/ui/pattern/mut_preserve_binding_mode_2021.rs index befa49fdc24..282e0ef95d2 100644 --- a/tests/ui/pattern/mut_preserve_binding_mode_2021.rs +++ b/tests/ui/pattern/mut_preserve_binding_mode_2021.rs @@ -1,6 +1,6 @@ //@ edition: 2021 //@ compile-flags: -Zunstable-options -#![feature(mut_preserve_binding_mode_2024)] +#![feature(ref_pat_eat_one_layer_2024)] #![allow(incomplete_features)] struct Foo(u8); diff --git a/tests/ui/pattern/mut_preserve_binding_mode_2024.rs b/tests/ui/pattern/mut_preserve_binding_mode_2024.rs index 5454962e16c..19aa73573b4 100644 --- a/tests/ui/pattern/mut_preserve_binding_mode_2024.rs +++ b/tests/ui/pattern/mut_preserve_binding_mode_2024.rs @@ -1,7 +1,7 @@ //@ run-pass //@ edition: 2024 //@ compile-flags: -Zunstable-options -#![feature(mut_preserve_binding_mode_2024)] +#![feature(mut_ref, ref_pat_eat_one_layer_2024)] #![allow(incomplete_features, unused)] struct Foo(u8); diff --git a/tests/ui/pattern/no_ref_mut_behind_and.rs b/tests/ui/pattern/no_ref_mut_behind_and.rs new file mode 100644 index 00000000000..c18d64904d0 --- /dev/null +++ b/tests/ui/pattern/no_ref_mut_behind_and.rs @@ -0,0 +1,9 @@ +//@ edition: 2021 +//@ run-pass +#![allow(incomplete_features)] +#![feature(ref_pat_eat_one_layer_2024)] + +fn main() { + let &[[x]] = &[&mut [42]]; + let _: &i32 = x; +} diff --git a/tests/ui/polymorphization/abi_mismatch.rs b/tests/ui/polymorphization/abi_mismatch.rs new file mode 100644 index 00000000000..22c2c162d1c --- /dev/null +++ b/tests/ui/polymorphization/abi_mismatch.rs @@ -0,0 +1,20 @@ +//! This test used to ICE: #123917 +//! The reason was that while the AST knows about two fields +//! named `ptr`, only one exists at the layout level, so accessing +//! `_extra_field` would use an oob index +//@ compile-flags: -Zmir-opt-level=5 -Zpolymorphize=on + +struct NonNull<T>(*mut T); + +struct Token<T> { + ptr: *mut T, + ptr: NonNull<T>, + //~^ ERROR: `ptr` is already declared + _extra_field: (), +} + +fn tokenize<T>(item: *mut T) -> Token<T> { + Token { ptr: NonNull(item), _extra_field: () } +} + +fn main() {} diff --git a/tests/ui/polymorphization/abi_mismatch.stderr b/tests/ui/polymorphization/abi_mismatch.stderr new file mode 100644 index 00000000000..e96c737f777 --- /dev/null +++ b/tests/ui/polymorphization/abi_mismatch.stderr @@ -0,0 +1,11 @@ +error[E0124]: field `ptr` is already declared + --> $DIR/abi_mismatch.rs:11:5 + | +LL | ptr: *mut T, + | ----------- `ptr` first declared here +LL | ptr: NonNull<T>, + | ^^^^^^^^^^^^^^^ field already declared + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0124`. diff --git a/tests/ui/privacy/ufc-method-call.different_name.stderr b/tests/ui/privacy/ufc-method-call.different_name.stderr new file mode 100644 index 00000000000..16496c480dd --- /dev/null +++ b/tests/ui/privacy/ufc-method-call.different_name.stderr @@ -0,0 +1,15 @@ +error[E0599]: no function or associated item named `foo` found for struct `Foo<B>` in the current scope + --> $DIR/ufc-method-call.rs:27:27 + | +LL | pub struct Foo<T>(T); + | ----------------- function or associated item `foo` not found for this struct +... +LL | test::Foo::<test::B>::foo(); + | ^^^ function or associated item not found in `Foo<B>` + | + = note: the function or associated item was found for + - `Foo<A>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/privacy/ufc-method-call.rs b/tests/ui/privacy/ufc-method-call.rs new file mode 100644 index 00000000000..525d9a9eee9 --- /dev/null +++ b/tests/ui/privacy/ufc-method-call.rs @@ -0,0 +1,30 @@ +//! This test used to report that the method call cannot +//! call the private method `Foo<A>::foo`, even though the user +//! explicitly selected `Foo<B>::foo`. This is because we only +//! looked for methods of the right name, without properly checking +//! the `Self` type + +//@ revisions: same_name different_name + +pub mod test { + pub struct A; + pub struct B; + pub struct Foo<T>(T); + + impl Foo<A> { + fn foo() {} + } + + impl Foo<B> { + #[cfg(same_name)] + fn foo() {} + #[cfg(different_name)] + fn bar() {} + } +} + +fn main() { + test::Foo::<test::B>::foo(); + //[same_name]~^ ERROR associated function `foo` is private + //[different_name]~^^ ERROR no function or associated item named `foo` found for struct `Foo<B>` +} diff --git a/tests/ui/issues/issue-53498.stderr b/tests/ui/privacy/ufc-method-call.same_name.stderr index 61a1aedf508..194ba42cbf9 100644 --- a/tests/ui/issues/issue-53498.stderr +++ b/tests/ui/privacy/ufc-method-call.same_name.stderr @@ -1,5 +1,5 @@ error[E0624]: associated function `foo` is private - --> $DIR/issue-53498.rs:16:27 + --> $DIR/ufc-method-call.rs:27:27 | LL | fn foo() {} | -------- private associated function defined here diff --git a/tests/ui/privacy/where-priv-type.rs b/tests/ui/privacy/where-priv-type.rs index cd9cce7ec3e..20467301ae1 100644 --- a/tests/ui/privacy/where-priv-type.rs +++ b/tests/ui/privacy/where-priv-type.rs @@ -11,55 +11,46 @@ pub struct PubTy; pub struct PubTyGeneric<T>(T); pub trait PubTr {} impl PubTr for PrivTy {} -pub trait PubTrWithAssocTy { type AssocTy; } -impl PubTrWithAssocTy for PrivTy { type AssocTy = PrivTy; } - +pub trait PubTrWithAssocTy { + type AssocTy; +} +impl PubTrWithAssocTy for PrivTy { + type AssocTy = PrivTy; +} pub struct S //~^ WARNING type `PrivTy` is more private than the item `S` where - PrivTy: -{} - + PrivTy:, {} pub enum E //~^ WARNING type `PrivTy` is more private than the item `E` where - PrivTy: -{} - + PrivTy:, {} pub fn f() //~^ WARNING type `PrivTy` is more private than the item `f` where - PrivTy: -{} - + PrivTy:, +{ +} impl S //~^ WARNING type `PrivTy` is more private than the item `S` where - PrivTy: + PrivTy:, { pub fn f() //~^ WARNING type `PrivTy` is more private than the item `S::f` where - PrivTy: - {} + PrivTy:, + { + } } +impl PubTr for PubTy where PrivTy: {} -impl PubTr for PubTy -where - PrivTy: -{} - - -impl<T> PubTr for PubTyGeneric<T> -where - T: PubTrWithAssocTy<AssocTy=PrivTy> -{} - +impl<T> PubTr for PubTyGeneric<T> where T: PubTrWithAssocTy<AssocTy = PrivTy> {} pub struct Const<const U: u8>; @@ -70,10 +61,11 @@ pub trait Trait { impl<const U: u8> Trait for Const<U> where - Const<{ my_const_fn(U) }>: , + Const<{ my_const_fn(U) }>:, { type AssocTy = Const<{ my_const_fn(U) }>; //~^ ERROR private type + //~| ERROR private type fn assoc_fn() -> Self::AssocTy { Const } diff --git a/tests/ui/privacy/where-priv-type.stderr b/tests/ui/privacy/where-priv-type.stderr index 126330b14a6..08963e07c35 100644 --- a/tests/ui/privacy/where-priv-type.stderr +++ b/tests/ui/privacy/where-priv-type.stderr @@ -1,5 +1,5 @@ warning: type `PrivTy` is more private than the item `S` - --> $DIR/where-priv-type.rs:18:1 + --> $DIR/where-priv-type.rs:21:1 | LL | pub struct S | ^^^^^^^^^^^^ struct `S` is reachable at visibility `pub` @@ -12,7 +12,7 @@ LL | struct PrivTy; = note: `#[warn(private_bounds)]` on by default warning: type `PrivTy` is more private than the item `E` - --> $DIR/where-priv-type.rs:25:1 + --> $DIR/where-priv-type.rs:26:1 | LL | pub enum E | ^^^^^^^^^^ enum `E` is reachable at visibility `pub` @@ -24,13 +24,13 @@ LL | struct PrivTy; | ^^^^^^^^^^^^^ warning: type `PrivTy` is more private than the item `f` - --> $DIR/where-priv-type.rs:32:1 + --> $DIR/where-priv-type.rs:31:1 | LL | / pub fn f() LL | | LL | | where -LL | | PrivTy: - | |___________^ function `f` is reachable at visibility `pub` +LL | | PrivTy:, + | |____________^ function `f` is reachable at visibility `pub` | note: but type `PrivTy` is only usable at visibility `pub(crate)` --> $DIR/where-priv-type.rs:8:1 @@ -39,13 +39,13 @@ LL | struct PrivTy; | ^^^^^^^^^^^^^ warning: type `PrivTy` is more private than the item `S` - --> $DIR/where-priv-type.rs:39:1 + --> $DIR/where-priv-type.rs:38:1 | LL | / impl S LL | | LL | | where -LL | | PrivTy: - | |___________^ implementation `S` is reachable at visibility `pub` +LL | | PrivTy:, + | |____________^ implementation `S` is reachable at visibility `pub` | note: but type `PrivTy` is only usable at visibility `pub(crate)` --> $DIR/where-priv-type.rs:8:1 @@ -54,13 +54,13 @@ LL | struct PrivTy; | ^^^^^^^^^^^^^ warning: type `PrivTy` is more private than the item `S::f` - --> $DIR/where-priv-type.rs:44:5 + --> $DIR/where-priv-type.rs:43:5 | LL | / pub fn f() LL | | LL | | where -LL | | PrivTy: - | |_______________^ associated function `S::f` is reachable at visibility `pub` +LL | | PrivTy:, + | |________________^ associated function `S::f` is reachable at visibility `pub` | note: but type `PrivTy` is only usable at visibility `pub(crate)` --> $DIR/where-priv-type.rs:8:1 @@ -69,7 +69,7 @@ LL | struct PrivTy; | ^^^^^^^^^^^^^ error[E0446]: private type `fn(u8) -> u8 {my_const_fn}` in public interface - --> $DIR/where-priv-type.rs:75:5 + --> $DIR/where-priv-type.rs:66:5 | LL | type AssocTy = Const<{ my_const_fn(U) }>; | ^^^^^^^^^^^^ can't leak private type @@ -77,6 +77,17 @@ LL | type AssocTy = Const<{ my_const_fn(U) }>; LL | const fn my_const_fn(val: u8) -> u8 { | ----------------------------------- `fn(u8) -> u8 {my_const_fn}` declared as private -error: aborting due to 1 previous error; 5 warnings emitted +error[E0446]: private type `fn(u8) -> u8 {my_const_fn}` in public interface + --> $DIR/where-priv-type.rs:66:5 + | +LL | type AssocTy = Const<{ my_const_fn(U) }>; + | ^^^^^^^^^^^^ can't leak private type +... +LL | const fn my_const_fn(val: u8) -> u8 { + | ----------------------------------- `fn(u8) -> u8 {my_const_fn}` declared as private + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors; 5 warnings emitted For more information about this error, try `rustc --explain E0446`. diff --git a/tests/ui/proc-macro/issue-81555.rs b/tests/ui/proc-macro/issue-81555.rs index b337ab7ce37..7a61a31952f 100644 --- a/tests/ui/proc-macro/issue-81555.rs +++ b/tests/ui/proc-macro/issue-81555.rs @@ -10,5 +10,6 @@ use test_macros::identity_attr; fn main() { let _x; let y = (); - (#[identity_attr] _x) = y; + #[identity_attr] + _x = y; } diff --git a/tests/ui/proc-macro/pretty-print-hack-show.local.stderr b/tests/ui/proc-macro/pretty-print-hack-show.local.stderr index 118882f73a3..889cd0c90eb 100644 --- a/tests/ui/proc-macro/pretty-print-hack-show.local.stderr +++ b/tests/ui/proc-macro/pretty-print-hack-show.local.stderr @@ -1,185 +1,6 @@ error: using an old version of `rental` - --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default - -error: using an old version of `rental` - --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: using an old version of `rental` - --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: using an old version of `rental` - --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: older versions of the `rental` crate no longer compile; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives -error: using an old version of `rental` - --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - -error: using an old version of `rental` - --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: using an old version of `rental` - --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: using an old version of `rental` - --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 8 previous errors - -Future incompatibility report: Future breakage diagnostic: -error: using an old version of `rental` - --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default - -Future breakage diagnostic: -error: using an old version of `rental` - --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default - -Future breakage diagnostic: -error: using an old version of `rental` - --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default - -Future breakage diagnostic: -error: using an old version of `rental` - --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default - -Future breakage diagnostic: -error: using an old version of `rental` - --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default - -Future breakage diagnostic: -error: using an old version of `rental` - --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default - -Future breakage diagnostic: -error: using an old version of `rental` - --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default - -Future breakage diagnostic: -error: using an old version of `rental` - --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default +error: aborting due to 1 previous error diff --git a/tests/ui/proc-macro/pretty-print-hack-show.local.stdout b/tests/ui/proc-macro/pretty-print-hack-show.local.stdout deleted file mode 100644 index 3d793d2a014..00000000000 --- a/tests/ui/proc-macro/pretty-print-hack-show.local.stdout +++ /dev/null @@ -1,44 +0,0 @@ -PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, } -PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input } -PRINT-DERIVE INPUT (DEBUG): TokenStream [ - Ident { - ident: "enum", - span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:1: 4:5 (#0), - }, - Ident { - ident: "ProceduralMasqueradeDummyType", - span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6: 4:35 (#0), - }, - Group { - delimiter: Brace, - stream: TokenStream [ - Ident { - ident: "Input", - span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:13:5: 13:10 (#0), - }, - ], - span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:36: 14:2 (#0), - }, -] -PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, } -PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input } -PRINT-DERIVE INPUT (DEBUG): TokenStream [ - Ident { - ident: "enum", - span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:1: 4:5 (#0), - }, - Ident { - ident: "ProceduralMasqueradeDummyType", - span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6: 4:35 (#0), - }, - Group { - delimiter: Brace, - stream: TokenStream [ - Ident { - ident: "Input", - span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:13:5: 13:10 (#0), - }, - ], - span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:36: 14:2 (#0), - }, -] diff --git a/tests/ui/proc-macro/pretty-print-hack-show.remapped.stderr b/tests/ui/proc-macro/pretty-print-hack-show.remapped.stderr index 118882f73a3..889cd0c90eb 100644 --- a/tests/ui/proc-macro/pretty-print-hack-show.remapped.stderr +++ b/tests/ui/proc-macro/pretty-print-hack-show.remapped.stderr @@ -1,185 +1,6 @@ error: using an old version of `rental` - --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default - -error: using an old version of `rental` - --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: using an old version of `rental` - --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: using an old version of `rental` - --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + = note: older versions of the `rental` crate no longer compile; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives -error: using an old version of `rental` - --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - -error: using an old version of `rental` - --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: using an old version of `rental` - --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: using an old version of `rental` - --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 8 previous errors - -Future incompatibility report: Future breakage diagnostic: -error: using an old version of `rental` - --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default - -Future breakage diagnostic: -error: using an old version of `rental` - --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default - -Future breakage diagnostic: -error: using an old version of `rental` - --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default - -Future breakage diagnostic: -error: using an old version of `rental` - --> $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default - -Future breakage diagnostic: -error: using an old version of `rental` - --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default - -Future breakage diagnostic: -error: using an old version of `rental` - --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default - -Future breakage diagnostic: -error: using an old version of `rental` - --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default - -Future breakage diagnostic: -error: using an old version of `rental` - --> $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6 - | -LL | enum ProceduralMasqueradeDummyType { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125> - = note: older versions of the `rental` crate will stop compiling in future versions of Rust; please update to `rental` v0.5.6, or switch to one of the `rental` alternatives - = note: `#[deny(proc_macro_back_compat)]` on by default +error: aborting due to 1 previous error diff --git a/tests/ui/proc-macro/pretty-print-hack-show.remapped.stdout b/tests/ui/proc-macro/pretty-print-hack-show.remapped.stdout deleted file mode 100644 index 3d793d2a014..00000000000 --- a/tests/ui/proc-macro/pretty-print-hack-show.remapped.stdout +++ /dev/null @@ -1,44 +0,0 @@ -PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, } -PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input } -PRINT-DERIVE INPUT (DEBUG): TokenStream [ - Ident { - ident: "enum", - span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:1: 4:5 (#0), - }, - Ident { - ident: "ProceduralMasqueradeDummyType", - span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:6: 4:35 (#0), - }, - Group { - delimiter: Brace, - stream: TokenStream [ - Ident { - ident: "Input", - span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:13:5: 13:10 (#0), - }, - ], - span: $DIR/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs:4:36: 14:2 (#0), - }, -] -PRINT-DERIVE INPUT (DISPLAY): enum ProceduralMasqueradeDummyType { Input, } -PRINT-DERIVE RE-COLLECTED (DISPLAY): enum ProceduralMasqueradeDummyType { Input } -PRINT-DERIVE INPUT (DEBUG): TokenStream [ - Ident { - ident: "enum", - span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:1: 4:5 (#0), - }, - Ident { - ident: "ProceduralMasqueradeDummyType", - span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:6: 4:35 (#0), - }, - Group { - delimiter: Brace, - stream: TokenStream [ - Ident { - ident: "Input", - span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:13:5: 13:10 (#0), - }, - ], - span: $DIR/pretty-print-hack/rental-0.5.5/src/lib.rs:4:36: 14:2 (#0), - }, -] diff --git a/tests/ui/pub/pub-ident-struct-4.fixed b/tests/ui/pub/pub-ident-struct-4.fixed index 5fedbb72437..a62ece43ece 100644 --- a/tests/ui/pub/pub-ident-struct-4.fixed +++ b/tests/ui/pub/pub-ident-struct-4.fixed @@ -1,6 +1,7 @@ //@ run-rustfix -pub struct T(#[allow(dead_code)] String); +#[allow(dead_code)] +pub struct T(String); //~^ ERROR missing `struct` for struct definition fn main() {} diff --git a/tests/ui/pub/pub-ident-struct-4.rs b/tests/ui/pub/pub-ident-struct-4.rs index 5c721c25a78..0d56a31beaf 100644 --- a/tests/ui/pub/pub-ident-struct-4.rs +++ b/tests/ui/pub/pub-ident-struct-4.rs @@ -1,6 +1,7 @@ //@ run-rustfix -pub T(#[allow(dead_code)] String); +#[allow(dead_code)] +pub T(String); //~^ ERROR missing `struct` for struct definition fn main() {} diff --git a/tests/ui/pub/pub-ident-struct-4.stderr b/tests/ui/pub/pub-ident-struct-4.stderr index 5fbb02c8673..ec136783211 100644 --- a/tests/ui/pub/pub-ident-struct-4.stderr +++ b/tests/ui/pub/pub-ident-struct-4.stderr @@ -1,12 +1,12 @@ error: missing `struct` for struct definition - --> $DIR/pub-ident-struct-4.rs:3:4 + --> $DIR/pub-ident-struct-4.rs:4:4 | -LL | pub T(#[allow(dead_code)] String); +LL | pub T(String); | ^ | help: add `struct` here to parse `T` as a public struct | -LL | pub struct T(#[allow(dead_code)] String); +LL | pub struct T(String); | ++++++ error: aborting due to 1 previous error diff --git a/tests/ui/pub/pub-reexport-priv-extern-crate.rs b/tests/ui/pub/pub-reexport-priv-extern-crate.rs index dd5cd420fa5..fb495be4001 100644 --- a/tests/ui/pub/pub-reexport-priv-extern-crate.rs +++ b/tests/ui/pub/pub-reexport-priv-extern-crate.rs @@ -1,5 +1,5 @@ extern crate core; -pub use core as reexported_core; //~ ERROR `core` is private, and cannot be re-exported +pub use core as reexported_core; //~ ERROR `core` is private and cannot be re-exported //~^ WARN this was previously accepted mod foo1 { diff --git a/tests/ui/pub/pub-reexport-priv-extern-crate.stderr b/tests/ui/pub/pub-reexport-priv-extern-crate.stderr index 3fa5b0f9aef..915d07fd08a 100644 --- a/tests/ui/pub/pub-reexport-priv-extern-crate.stderr +++ b/tests/ui/pub/pub-reexport-priv-extern-crate.stderr @@ -22,7 +22,7 @@ note: the crate import `core` is defined here LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ -error[E0365]: extern crate `core` is private, and cannot be re-exported, consider declaring with `pub` +error[E0365]: extern crate `core` is private and cannot be re-exported --> $DIR/pub-reexport-priv-extern-crate.rs:2:9 | LL | pub use core as reexported_core; @@ -31,6 +31,10 @@ LL | pub use core as reexported_core; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #34537 <https://github.com/rust-lang/rust/issues/34537> = note: `#[deny(pub_use_of_private_extern_crate)]` on by default +help: consider making the `extern crate` item publicly accessible + | +LL | pub extern crate core; + | +++ error: aborting due to 3 previous errors diff --git a/tests/ui/regions/regions-issue-21422.rs b/tests/ui/regions/regions-issue-21422.rs index 54beed9b3ac..67852a6f5de 100644 --- a/tests/ui/regions/regions-issue-21422.rs +++ b/tests/ui/regions/regions-issue-21422.rs @@ -5,6 +5,7 @@ //@ pretty-expanded FIXME #23616 +#[allow(dead_code)] pub struct P<'a> { _ptr: *const &'a u8, } diff --git a/tests/ui/resolve/filter-intrinsics.rs b/tests/ui/resolve/filter-intrinsics.rs index c0956ef85af..8d6d22817dc 100644 --- a/tests/ui/resolve/filter-intrinsics.rs +++ b/tests/ui/resolve/filter-intrinsics.rs @@ -1,6 +1,6 @@ fn main() { - // Should suggest only `std::mem::size_of` - let _ = size_of::<usize>(); + // Should suggest only `std::mem::transmute` + let _ = transmute::<usize>(); //~^ ERROR cannot find // Should suggest `std::intrinsics::fabsf64`, diff --git a/tests/ui/resolve/filter-intrinsics.stderr b/tests/ui/resolve/filter-intrinsics.stderr index cc1092dd0cf..9c9e92f6d4f 100644 --- a/tests/ui/resolve/filter-intrinsics.stderr +++ b/tests/ui/resolve/filter-intrinsics.stderr @@ -1,12 +1,12 @@ -error[E0425]: cannot find function `size_of` in this scope +error[E0425]: cannot find function `transmute` in this scope --> $DIR/filter-intrinsics.rs:3:13 | -LL | let _ = size_of::<usize>(); - | ^^^^^^^ not found in this scope +LL | let _ = transmute::<usize>(); + | ^^^^^^^^^ not found in this scope | help: consider importing this function | -LL + use std::mem::size_of; +LL + use std::mem::transmute; | error[E0425]: cannot find function `fabsf64` in this scope diff --git a/tests/ui/resolve/issue-82865.stderr b/tests/ui/resolve/issue-82865.stderr index 9d0439d9d87..730fd6d6026 100644 --- a/tests/ui/resolve/issue-82865.stderr +++ b/tests/ui/resolve/issue-82865.stderr @@ -15,13 +15,6 @@ LL | Box::z LL | mac!(); | ------ in this macro invocation | -note: if you're trying to build a new `Box<_, _>` consider using one of the following associated functions: - Box::<T>::new - Box::<T>::new_uninit - Box::<T>::new_zeroed - Box::<T>::try_new - and 18 others - --> $SRC_DIR/alloc/src/boxed.rs:LL:COL = 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 diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.rs index 402efaf5027..ea9d48e7859 100644 --- a/tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.rs +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/dlltool-failed.rs @@ -3,8 +3,8 @@ //@ needs-dlltool //@ compile-flags: --crate-type lib --emit link //@ normalize-stderr-test: "[^ ']*/dlltool.exe" -> "$$DLLTOOL" -//@ normalize-stderr-test: "[^ ]*/foo.def" -> "$$DEF_FILE" -//@ normalize-stderr-test: "[^ ]*/foo.lib" -> "$$LIB_FILE" +//@ normalize-stderr-test: "[^ ]*/foo.dll_imports.def" -> "$$DEF_FILE" +//@ normalize-stderr-test: "[^ ]*/foo.dll_imports.lib" -> "$$LIB_FILE" //@ normalize-stderr-test: "-m [^ ]*" -> "$$TARGET_MACHINE" //@ normalize-stderr-test: "-f [^ ]*" -> "$$ASM_FLAGS" //@ normalize-stderr-test: "--temp-prefix [^ ]*/foo.dll" -> "$$TEMP_PREFIX" diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.rs new file mode 100644 index 00000000000..6b5ba5bb624 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.rs @@ -0,0 +1,22 @@ +//@ check-fail +// Fixes #119830 + +#![feature(effects)] +#![feature(min_specialization)] +#![feature(const_trait_impl)] + +trait Specialize {} + +trait Foo {} + +impl<T> const Foo for T {} +//~^ error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` +//~| error: the const parameter `host` is not constrained by the impl trait, self type, or predicates [E0207] + +impl<T> const Foo for T where T: const Specialize {} +//~^ error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` +//~| error: `const` can only be applied to `#[const_trait]` traits +//~| error: the const parameter `host` is not constrained by the impl trait, self type, or predicates [E0207] +//~| error: conflicting implementations of trait `Foo` + +fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.stderr new file mode 100644 index 00000000000..70dd0350dc4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/spec-effectvar-ice.stderr @@ -0,0 +1,61 @@ +error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` + --> $DIR/spec-effectvar-ice.rs:12:15 + | +LL | trait Foo {} + | - help: mark `Foo` as const: `#[const_trait]` +LL | +LL | impl<T> const Foo for T {} + | ^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` + --> $DIR/spec-effectvar-ice.rs:16:15 + | +LL | trait Foo {} + | - help: mark `Foo` as const: `#[const_trait]` +... +LL | impl<T> const Foo for T where T: const Specialize {} + | ^^^ + | + = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` + = note: adding a non-const method body in the future would be a breaking change + +error: `const` can only be applied to `#[const_trait]` traits + --> $DIR/spec-effectvar-ice.rs:16:40 + | +LL | impl<T> const Foo for T where T: const Specialize {} + | ^^^^^^^^^^ + +error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates + --> $DIR/spec-effectvar-ice.rs:12:9 + | +LL | impl<T> const Foo for T {} + | ^^^^^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error[E0119]: conflicting implementations of trait `Foo` + --> $DIR/spec-effectvar-ice.rs:16:1 + | +LL | impl<T> const Foo for T {} + | ----------------------- first implementation here +... +LL | impl<T> const Foo for T where T: const Specialize {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + +error[E0207]: the const parameter `host` is not constrained by the impl trait, self type, or predicates + --> $DIR/spec-effectvar-ice.rs:16:9 + | +LL | impl<T> const Foo for T where T: const Specialize {} + | ^^^^^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0119, E0207. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/rust-2018/macro-use-warned-against.rs b/tests/ui/rust-2018/macro-use-warned-against.rs index 1e78acf201d..d6bb5150178 100644 --- a/tests/ui/rust-2018/macro-use-warned-against.rs +++ b/tests/ui/rust-2018/macro-use-warned-against.rs @@ -4,7 +4,7 @@ #![warn(macro_use_extern_crate, unused)] -#[macro_use] //~ WARN should be replaced at use sites with a `use` item +#[macro_use] //~ WARN applying the `#[macro_use]` attribute to an `extern crate` item is deprecated extern crate macro_use_warned_against; #[macro_use] //~ WARN unused `#[macro_use]` extern crate macro_use_warned_against2; diff --git a/tests/ui/rust-2018/macro-use-warned-against.stderr b/tests/ui/rust-2018/macro-use-warned-against.stderr index 6b46f002e32..3ac1f127051 100644 --- a/tests/ui/rust-2018/macro-use-warned-against.stderr +++ b/tests/ui/rust-2018/macro-use-warned-against.stderr @@ -1,9 +1,10 @@ -warning: deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead +warning: applying the `#[macro_use]` attribute to an `extern crate` item is deprecated --> $DIR/macro-use-warned-against.rs:7:1 | LL | #[macro_use] | ^^^^^^^^^^^^ | + = help: remove it and import macros at use sites with a `use` item instead note: the lint level is defined here --> $DIR/macro-use-warned-against.rs:5:9 | diff --git a/tests/ui/rust-2024/unsafe-env.e2021.stderr b/tests/ui/rust-2024/unsafe-env.e2021.stderr index cc40ec2e466..90c1df192aa 100644 --- a/tests/ui/rust-2024/unsafe-env.e2021.stderr +++ b/tests/ui/rust-2024/unsafe-env.e2021.stderr @@ -1,5 +1,24 @@ +error[E0133]: call to unsafe function `unsafe_fn` is unsafe and requires unsafe block + --> $DIR/unsafe-env.rs:15:9 + | +LL | unsafe_fn(); + | ^^^^^^^^^^^ call to unsafe function + | + = note: for more information, see issue #71668 <https://github.com/rust-lang/rust/issues/71668> + = note: consult the function's documentation for information on how to avoid undefined behavior +note: an unsafe function restricts its caller, but its body is safe by default + --> $DIR/unsafe-env.rs:9:1 + | +LL | unsafe fn unsafe_fn() { + | ^^^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/unsafe-env.rs:8:8 + | +LL | #[deny(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^ + error[E0133]: call to unsafe function `unsafe_fn` is unsafe and requires unsafe function or block - --> $DIR/unsafe-env.rs:23:5 + --> $DIR/unsafe-env.rs:33:5 | LL | unsafe_fn(); | ^^^^^^^^^^^ call to unsafe function @@ -7,17 +26,17 @@ LL | unsafe_fn(); = note: consult the function's documentation for information on how to avoid undefined behavior error: unnecessary `unsafe` block - --> $DIR/unsafe-env.rs:26:5 + --> $DIR/unsafe-env.rs:36:5 | LL | unsafe { | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/unsafe-env.rs:11:8 + --> $DIR/unsafe-env.rs:21:8 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rust-2024/unsafe-env.e2024.stderr b/tests/ui/rust-2024/unsafe-env.e2024.stderr index b43f817cf72..5ecdf3cd7a7 100644 --- a/tests/ui/rust-2024/unsafe-env.e2024.stderr +++ b/tests/ui/rust-2024/unsafe-env.e2024.stderr @@ -1,5 +1,42 @@ +error[E0133]: call to unsafe function `std::env::set_var` is unsafe and requires unsafe block + --> $DIR/unsafe-env.rs:10:5 + | +LL | env::set_var("FOO", "BAR"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: for more information, see issue #71668 <https://github.com/rust-lang/rust/issues/71668> + = note: consult the function's documentation for information on how to avoid undefined behavior +note: an unsafe function restricts its caller, but its body is safe by default + --> $DIR/unsafe-env.rs:9:1 + | +LL | unsafe fn unsafe_fn() { + | ^^^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/unsafe-env.rs:8:8 + | +LL | #[deny(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0133]: call to unsafe function `std::env::remove_var` is unsafe and requires unsafe block + --> $DIR/unsafe-env.rs:12:5 + | +LL | env::remove_var("FOO"); + | ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: for more information, see issue #71668 <https://github.com/rust-lang/rust/issues/71668> + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function `unsafe_fn` is unsafe and requires unsafe block + --> $DIR/unsafe-env.rs:15:9 + | +LL | unsafe_fn(); + | ^^^^^^^^^^^ call to unsafe function + | + = note: for more information, see issue #71668 <https://github.com/rust-lang/rust/issues/71668> + = note: consult the function's documentation for information on how to avoid undefined behavior + error[E0133]: call to unsafe function `set_var` is unsafe and requires unsafe block - --> $DIR/unsafe-env.rs:13:5 + --> $DIR/unsafe-env.rs:23:5 | LL | env::set_var("FOO", "BAR"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function @@ -7,7 +44,7 @@ LL | env::set_var("FOO", "BAR"); = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: call to unsafe function `remove_var` is unsafe and requires unsafe block - --> $DIR/unsafe-env.rs:15:5 + --> $DIR/unsafe-env.rs:25:5 | LL | env::remove_var("FOO"); | ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function @@ -15,7 +52,7 @@ LL | env::remove_var("FOO"); = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: call to unsafe function `unsafe_fn` is unsafe and requires unsafe block - --> $DIR/unsafe-env.rs:23:5 + --> $DIR/unsafe-env.rs:33:5 | LL | unsafe_fn(); | ^^^^^^^^^^^ call to unsafe function @@ -23,17 +60,17 @@ LL | unsafe_fn(); = note: consult the function's documentation for information on how to avoid undefined behavior error: unnecessary `unsafe` block - --> $DIR/unsafe-env.rs:26:5 + --> $DIR/unsafe-env.rs:36:5 | LL | unsafe { | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/unsafe-env.rs:11:8 + --> $DIR/unsafe-env.rs:21:8 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rust-2024/unsafe-env.rs b/tests/ui/rust-2024/unsafe-env.rs index a882f077b9b..601f44e1d3e 100644 --- a/tests/ui/rust-2024/unsafe-env.rs +++ b/tests/ui/rust-2024/unsafe-env.rs @@ -5,7 +5,17 @@ use std::env; -unsafe fn unsafe_fn() {} +#[deny(unsafe_op_in_unsafe_fn)] +unsafe fn unsafe_fn() { + env::set_var("FOO", "BAR"); + //[e2024]~^ ERROR call to unsafe function `std::env::set_var` is unsafe + env::remove_var("FOO"); + //[e2024]~^ ERROR call to unsafe function `std::env::remove_var` is unsafe + if false { + unsafe_fn(); + //~^ ERROR call to unsafe function `unsafe_fn` is unsafe + } +} fn safe_fn() {} #[deny(unused_unsafe)] diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr new file mode 100644 index 00000000000..3a99caa719b --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2021.stderr @@ -0,0 +1,19 @@ +error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe function or block + --> $DIR/extern-items-unsafe.rs:14:5 + | +LL | test1(TEST1); + | ^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/extern-items-unsafe.rs:14:11 + | +LL | test1(TEST1); + | ^^^^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr new file mode 100644 index 00000000000..fcf937b7ac5 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.edition2024.stderr @@ -0,0 +1,19 @@ +error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe block + --> $DIR/extern-items-unsafe.rs:14:5 + | +LL | test1(TEST1); + | ^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: use of extern static is unsafe and requires unsafe block + --> $DIR/extern-items-unsafe.rs:14:11 + | +LL | test1(TEST1); + | ^^^^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs new file mode 100644 index 00000000000..ad569a256db --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items-unsafe.rs @@ -0,0 +1,25 @@ +//@ revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 +//@[edition2024] compile-flags: -Zunstable-options + +#![feature(unsafe_extern_blocks)] + +unsafe extern "C" { + static TEST1: i32; + fn test1(i: i32); +} + +fn test2() { + test1(TEST1); + //~^ ERROR: call to unsafe function `test1` is unsafe + //~| ERROR: use of extern static is unsafe +} + +fn test3() { + unsafe { + test1(TEST1); + } +} + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr new file mode 100644 index 00000000000..d456cfc6829 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.edition2024.stderr @@ -0,0 +1,12 @@ +error: extern blocks must be unsafe + --> $DIR/extern-items.rs:9:1 + | +LL | / extern "C" { +LL | | +LL | | static TEST1: i32; +LL | | fn test1(i: i32); +LL | | } + | |_^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs new file mode 100644 index 00000000000..16fa1bbb8a4 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/extern-items.rs @@ -0,0 +1,20 @@ +//@ revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2021] check-pass +//@[edition2024] edition:2024 +//@[edition2024] compile-flags: -Zunstable-options + +#![feature(unsafe_extern_blocks)] + +extern "C" { + //[edition2024]~^ ERROR extern blocks must be unsafe + static TEST1: i32; + fn test1(i: i32); +} + +unsafe extern "C" { + static TEST2: i32; + fn test2(i: i32); +} + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs new file mode 100644 index 00000000000..74cd5621fce --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs @@ -0,0 +1,18 @@ +//@ revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 +//@[edition2024] compile-flags: -Zunstable-options +//@ check-pass + +#![feature(unsafe_extern_blocks)] + +unsafe extern "C" { + safe static TEST1: i32; + safe fn test1(i: i32); +} + +fn test2() { + test1(TEST1); +} + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr new file mode 100644 index 00000000000..411cf48b486 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr @@ -0,0 +1,20 @@ +error: items in unadorned `extern` blocks cannot have safety qualifiers + --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5 + | +LL | extern "C" { + | ---------- help: add unsafe to this `extern` block +LL | +LL | safe static TEST1: i32; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: items in unadorned `extern` blocks cannot have safety qualifiers + --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:12:5 + | +LL | extern "C" { + | ---------- help: add unsafe to this `extern` block +... +LL | safe fn test1(i: i32); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr new file mode 100644 index 00000000000..b634adc2999 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr @@ -0,0 +1,32 @@ +error: extern blocks must be unsafe + --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:8:1 + | +LL | / extern "C" { +LL | | +LL | | safe static TEST1: i32; +LL | | +LL | | safe fn test1(i: i32); +LL | | +LL | | } + | |_^ + +error: items in unadorned `extern` blocks cannot have safety qualifiers + --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5 + | +LL | extern "C" { + | ---------- help: add unsafe to this `extern` block +LL | +LL | safe static TEST1: i32; + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: items in unadorned `extern` blocks cannot have safety qualifiers + --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:12:5 + | +LL | extern "C" { + | ---------- help: add unsafe to this `extern` block +... +LL | safe fn test1(i: i32); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs new file mode 100644 index 00000000000..11f55cb195f --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.rs @@ -0,0 +1,20 @@ +//@ revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 +//@[edition2024] compile-flags: -Zunstable-options + +#![feature(unsafe_extern_blocks)] + +extern "C" { + //[edition2024]~^ ERROR extern blocks must be unsafe + safe static TEST1: i32; + //~^ ERROR items in unadorned `extern` blocks cannot have safety qualifiers + safe fn test1(i: i32); + //~^ ERROR items in unadorned `extern` blocks cannot have safety qualifiers +} + +fn test2() { + test1(TEST1); +} + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.fixed b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.fixed new file mode 100644 index 00000000000..10c19759d8a --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.fixed @@ -0,0 +1,19 @@ +//@ run-rustfix + +#![feature(unsafe_extern_blocks)] +#![deny(missing_unsafe_on_extern)] +#![allow(unused)] + +unsafe extern "C" { + //~^ ERROR extern blocks should be unsafe [missing_unsafe_on_extern] + //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! + static TEST1: i32; + fn test1(i: i32); +} + +unsafe extern "C" { + static TEST2: i32; + fn test2(i: i32); +} + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.rs b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.rs new file mode 100644 index 00000000000..b81e52ddc58 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.rs @@ -0,0 +1,19 @@ +//@ run-rustfix + +#![feature(unsafe_extern_blocks)] +#![deny(missing_unsafe_on_extern)] +#![allow(unused)] + +extern "C" { + //~^ ERROR extern blocks should be unsafe [missing_unsafe_on_extern] + //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! + static TEST1: i32; + fn test1(i: i32); +} + +unsafe extern "C" { + static TEST2: i32; + fn test2(i: i32); +} + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr new file mode 100644 index 00000000000..0a3c2cd25e3 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-extern-suggestion.stderr @@ -0,0 +1,25 @@ +error: extern blocks should be unsafe + --> $DIR/unsafe-extern-suggestion.rs:7:1 + | +LL | extern "C" { + | ^ + | | + | _help: needs `unsafe` before the extern keyword: `unsafe` + | | +LL | | +LL | | +LL | | static TEST1: i32; +LL | | fn test1(i: i32); +LL | | } + | |_^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! + = note: for more information, see issue #123743 <https://github.com/rust-lang/rust/issues/123743> +note: the lint level is defined here + --> $DIR/unsafe-extern-suggestion.rs:4:9 + | +LL | #![deny(missing_unsafe_on_extern)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr new file mode 100644 index 00000000000..8bb7ffefeea --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2021.stderr @@ -0,0 +1,19 @@ +error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe function or block + --> $DIR/unsafe-items.rs:20:5 + | +LL | test1(TEST1); + | ^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/unsafe-items.rs:20:11 + | +LL | test1(TEST1); + | ^^^^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr new file mode 100644 index 00000000000..9a30142a632 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.edition2024.stderr @@ -0,0 +1,19 @@ +error[E0133]: call to unsafe function `test1` is unsafe and requires unsafe block + --> $DIR/unsafe-items.rs:20:5 + | +LL | test1(TEST1); + | ^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: use of extern static is unsafe and requires unsafe block + --> $DIR/unsafe-items.rs:20:11 + | +LL | test1(TEST1); + | ^^^^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs new file mode 100644 index 00000000000..9066953abc6 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-items.rs @@ -0,0 +1,25 @@ +//@ revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 +//@[edition2024] compile-flags: -Zunstable-options + +#![feature(unsafe_extern_blocks)] + +unsafe extern "C" { + unsafe static TEST1: i32; + unsafe fn test1(i: i32); +} + +fn test2() { + unsafe { + test1(TEST1); + } +} + +fn test3() { + test1(TEST1); + //~^ ERROR: call to unsafe function `test1` is unsafe + //~| ERROR: use of extern static is unsafe +} + +fn main() {} diff --git a/tests/ui/specialization/anyid-repro-125197.rs b/tests/ui/specialization/anyid-repro-125197.rs new file mode 100644 index 00000000000..9428d8dc2d4 --- /dev/null +++ b/tests/ui/specialization/anyid-repro-125197.rs @@ -0,0 +1,17 @@ +//@ aux-build: anyid-repro-125197.rs +//@ check-pass + +// Makes sure that we don't check `specializes(impl1, impl2)` for a pair of impls that don't +// actually participate in specialization. Since <https://github.com/rust-lang/rust/pull/122791>, +// we don't treat inductive cycles as errors -- so we may need to winnow more pairs of impls, and +// we try to winnow impls in favor of other impls. However, if we're *inside* the `specializes` +// query, then may have a query cycle if we call `specializes` again! + +extern crate anyid_repro_125197; +use anyid_repro_125197::AnyId; + +fn main() { + let x = "hello, world"; + let y: AnyId = x.into(); + let _ = y == x; +} diff --git a/tests/ui/specialization/auxiliary/anyid-repro-125197.rs b/tests/ui/specialization/auxiliary/anyid-repro-125197.rs new file mode 100644 index 00000000000..c2794959740 --- /dev/null +++ b/tests/ui/specialization/auxiliary/anyid-repro-125197.rs @@ -0,0 +1,26 @@ +use std::fmt::Display; +use std::sync::Arc; + +pub struct AnyId(()); + +impl PartialEq<Self> for AnyId { + fn eq(&self, _: &Self) -> bool { + todo!() + } +} + +impl<T: Identifier> PartialEq<T> for AnyId { + fn eq(&self, _: &T) -> bool { + todo!() + } +} + +impl<T: Identifier> From<T> for AnyId { + fn from(_: T) -> Self { + todo!() + } +} + +pub trait Identifier: Display + 'static {} + +impl<T> Identifier for T where T: PartialEq + Display + 'static {} diff --git a/tests/ui/specialization/dont-drop-upcast-candidate.rs b/tests/ui/specialization/dont-drop-upcast-candidate.rs new file mode 100644 index 00000000000..98d8cad7c1f --- /dev/null +++ b/tests/ui/specialization/dont-drop-upcast-candidate.rs @@ -0,0 +1,13 @@ +#![feature(unsize)] + +use std::marker::Unsize; +use std::ops::Deref; + +trait Foo: Bar {} +trait Bar {} + +impl<T> Bar for T where dyn Foo: Unsize<dyn Bar> {} +impl Bar for () {} +//~^ ERROR conflicting implementations of trait `Bar` for type `()` + +fn main() {} diff --git a/tests/ui/specialization/dont-drop-upcast-candidate.stderr b/tests/ui/specialization/dont-drop-upcast-candidate.stderr new file mode 100644 index 00000000000..dc0c54f9aa8 --- /dev/null +++ b/tests/ui/specialization/dont-drop-upcast-candidate.stderr @@ -0,0 +1,11 @@ +error[E0119]: conflicting implementations of trait `Bar` for type `()` + --> $DIR/dont-drop-upcast-candidate.rs:10:1 + | +LL | impl<T> Bar for T where dyn Foo: Unsize<dyn Bar> {} + | ------------------------------------------------ first implementation here +LL | impl Bar for () {} + | ^^^^^^^^^^^^^^^ conflicting implementation for `()` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/crashes/124464.rs b/tests/ui/static/duplicated-fields-issue-124464.rs index 471479f5cf1..60609edbfeb 100644 --- a/tests/crashes/124464.rs +++ b/tests/ui/static/duplicated-fields-issue-124464.rs @@ -1,12 +1,16 @@ -//@ known-bug: rust-lang/rust #124464 +// Don't const eval fields with ambiguous layout. +// See issues #125842 and #124464. + enum TestOption<T> { TestSome(T), TestSome(T), +//~^ ERROR the name `TestSome` is defined multiple times } pub struct Request { bar: TestOption<u64>, bar: u8, +//~^ ERROR field `bar` is already declared } fn default_instance() -> &'static Request { diff --git a/tests/ui/static/duplicated-fields-issue-124464.stderr b/tests/ui/static/duplicated-fields-issue-124464.stderr new file mode 100644 index 00000000000..a36192ae8d6 --- /dev/null +++ b/tests/ui/static/duplicated-fields-issue-124464.stderr @@ -0,0 +1,22 @@ +error[E0428]: the name `TestSome` is defined multiple times + --> $DIR/duplicated-fields-issue-124464.rs:6:5 + | +LL | TestSome(T), + | ----------- previous definition of the type `TestSome` here +LL | TestSome(T), + | ^^^^^^^^^^^ `TestSome` redefined here + | + = note: `TestSome` must be defined only once in the type namespace of this enum + +error[E0124]: field `bar` is already declared + --> $DIR/duplicated-fields-issue-124464.rs:12:5 + | +LL | bar: TestOption<u64>, + | -------------------- `bar` first declared here +LL | bar: u8, + | ^^^^^^^ field already declared + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0124, E0428. +For more information about an error, try `rustc --explain E0124`. diff --git a/tests/ui/static/duplicated-fields-issue-125842.rs b/tests/ui/static/duplicated-fields-issue-125842.rs new file mode 100644 index 00000000000..580b810232e --- /dev/null +++ b/tests/ui/static/duplicated-fields-issue-125842.rs @@ -0,0 +1,21 @@ +// Do not try to evaluate static initalizers that reference +// ill-defined types. This used to be an ICE. +// See issues #125842 and #124464. +struct Struct { + field: Option<u8>, + field: u8, +//~^ ERROR field `field` is already declared +} + +static STATIC_A: Struct = Struct { + field: 1 +}; + +static STATIC_B: Struct = { + let field = 1; + Struct { + field, + } +}; + +fn main() {} diff --git a/tests/ui/static/duplicated-fields-issue-125842.stderr b/tests/ui/static/duplicated-fields-issue-125842.stderr new file mode 100644 index 00000000000..c80bb99005e --- /dev/null +++ b/tests/ui/static/duplicated-fields-issue-125842.stderr @@ -0,0 +1,11 @@ +error[E0124]: field `field` is already declared + --> $DIR/duplicated-fields-issue-125842.rs:6:5 + | +LL | field: Option<u8>, + | ----------------- `field` first declared here +LL | field: u8, + | ^^^^^^^^^ field already declared + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0124`. diff --git a/tests/ui/structs-enums/newtype-struct-with-dtor.rs b/tests/ui/structs-enums/newtype-struct-with-dtor.rs index 19672e41c9a..16439a7fedd 100644 --- a/tests/ui/structs-enums/newtype-struct-with-dtor.rs +++ b/tests/ui/structs-enums/newtype-struct-with-dtor.rs @@ -3,8 +3,10 @@ #![allow(unused_variables)] //@ pretty-expanded FIXME #23616 +#[allow(dead_code)] pub struct Fd(u32); +#[allow(dead_code)] fn foo(a: u32) {} impl Drop for Fd { diff --git a/tests/ui/structs-enums/uninstantiable-struct.rs b/tests/ui/structs-enums/uninstantiable-struct.rs index 97bc7d8414e..1074dbcd6e6 100644 --- a/tests/ui/structs-enums/uninstantiable-struct.rs +++ b/tests/ui/structs-enums/uninstantiable-struct.rs @@ -1,4 +1,5 @@ //@ run-pass -pub struct Z(#[allow(dead_code)] &'static Z); +#[allow(dead_code)] +pub struct Z(&'static Z); pub fn main() {} diff --git a/tests/ui/suggestions/derive-clone-for-eq.fixed b/tests/ui/suggestions/derive-clone-for-eq.fixed index 4dc362f9478..cf800c6e47d 100644 --- a/tests/ui/suggestions/derive-clone-for-eq.fixed +++ b/tests/ui/suggestions/derive-clone-for-eq.fixed @@ -1,6 +1,7 @@ //@ run-rustfix // https://github.com/rust-lang/rust/issues/79076 +#[allow(dead_code)] #[derive(Clone, Eq)] //~ ERROR [E0277] pub struct Struct<T: std::clone::Clone>(T); diff --git a/tests/ui/suggestions/derive-clone-for-eq.rs b/tests/ui/suggestions/derive-clone-for-eq.rs index b3635000f16..84736426bac 100644 --- a/tests/ui/suggestions/derive-clone-for-eq.rs +++ b/tests/ui/suggestions/derive-clone-for-eq.rs @@ -1,6 +1,7 @@ //@ run-rustfix // https://github.com/rust-lang/rust/issues/79076 +#[allow(dead_code)] #[derive(Clone, Eq)] //~ ERROR [E0277] pub struct Struct<T>(T); diff --git a/tests/ui/suggestions/derive-clone-for-eq.stderr b/tests/ui/suggestions/derive-clone-for-eq.stderr index 6fae6e1316d..54670fbffcf 100644 --- a/tests/ui/suggestions/derive-clone-for-eq.stderr +++ b/tests/ui/suggestions/derive-clone-for-eq.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `T: Clone` is not satisfied - --> $DIR/derive-clone-for-eq.rs:4:17 + --> $DIR/derive-clone-for-eq.rs:5:17 | LL | #[derive(Clone, Eq)] | ^^ the trait `Clone` is not implemented for `T`, which is required by `Struct<T>: PartialEq` | note: required for `Struct<T>` to implement `PartialEq` - --> $DIR/derive-clone-for-eq.rs:7:19 + --> $DIR/derive-clone-for-eq.rs:8:19 | LL | impl<T: Clone, U> PartialEq<U> for Struct<T> | ----- ^^^^^^^^^^^^ ^^^^^^^^^ diff --git a/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.rs b/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.rs new file mode 100644 index 00000000000..efa296db47c --- /dev/null +++ b/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.rs @@ -0,0 +1,11 @@ +// Regression test for ICE #125876 + +fn main() { + std::ptr::from_ref(num).cast_mut().as_deref(); + //~^ ERROR cannot find value `num` in this scope + //~| ERROR no method named `as_deref` found for raw pointer `*mut _` in the current scope + //~| WARN type annotations needed + //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + //~| WARN type annotations needed + //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! +} diff --git a/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr b/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr new file mode 100644 index 00000000000..d610a3b7cad --- /dev/null +++ b/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr @@ -0,0 +1,40 @@ +error[E0425]: cannot find value `num` in this scope + --> $DIR/ice-unwrap-probe-many-result-125876.rs:4:24 + | +LL | std::ptr::from_ref(num).cast_mut().as_deref(); + | ^^^ not found in this scope + +warning: type annotations needed + --> $DIR/ice-unwrap-probe-many-result-125876.rs:4:29 + | +LL | std::ptr::from_ref(num).cast_mut().as_deref(); + | ^^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906> + = note: `#[warn(tyvar_behind_raw_pointer)]` on by default + +warning: type annotations needed + --> $DIR/ice-unwrap-probe-many-result-125876.rs:4:40 + | +LL | std::ptr::from_ref(num).cast_mut().as_deref(); + | ^^^^^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906> + +error[E0599]: no method named `as_deref` found for raw pointer `*mut _` in the current scope + --> $DIR/ice-unwrap-probe-many-result-125876.rs:4:40 + | +LL | std::ptr::from_ref(num).cast_mut().as_deref(); + | ^^^^^^^^ + | +help: there is a method `as_ref` with a similar name + | +LL | std::ptr::from_ref(num).cast_mut().as_ref(); + | ~~~~~~ + +error: aborting due to 2 previous errors; 2 warnings emitted + +Some errors have detailed explanations: E0425, E0599. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/suggestions/missing-lifetime-specifier.rs b/tests/ui/suggestions/missing-lifetime-specifier.rs index cd7fa0c1d85..dd437fc0c0b 100644 --- a/tests/ui/suggestions/missing-lifetime-specifier.rs +++ b/tests/ui/suggestions/missing-lifetime-specifier.rs @@ -1,6 +1,11 @@ -// different number of duplicated diagnostics on different targets -//@ only-x86_64 -//@ only-linux +// The specific errors produced depend the thread-local implementation. +// Run only on platforms with "fast" TLS. +//@ ignore-windows FIXME(#84933) +//@ ignore-wasm globals are used instead of thread locals +//@ ignore-emscripten globals are used instead of thread locals +//@ ignore-android does not use #[thread_local] +//@ ignore-nto does not use #[thread_local] +// Different number of duplicated diagnostics on different targets //@ compile-flags: -Zdeduplicate-diagnostics=yes #![allow(bare_trait_objects)] @@ -21,23 +26,19 @@ trait Tar<'t, 'k, I> {} thread_local! { static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::new()); - //~^ ERROR missing lifetime specifiers - //~| ERROR missing lifetime specifiers + //~^ ERROR missing lifetime specifiers } thread_local! { static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new()); - //~^ ERROR missing lifetime specifiers - //~| ERROR missing lifetime specifiers + //~^ ERROR missing lifetime specifiers } thread_local! { static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new()); //~^ ERROR missing lifetime specifiers - //~| ERROR missing lifetime specifiers } thread_local! { static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new()); //~^ ERROR missing lifetime specifiers - //~| ERROR missing lifetime specifiers } thread_local! { @@ -47,8 +48,7 @@ thread_local! { thread_local! { static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); //~^ ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied - //~| ERROR missing lifetime - //~| ERROR missing lifetime + //~| ERROR missing lifetime specifier } fn main() {} diff --git a/tests/ui/suggestions/missing-lifetime-specifier.stderr b/tests/ui/suggestions/missing-lifetime-specifier.stderr index 2b85cfde7b6..e0b6bb872b5 100644 --- a/tests/ui/suggestions/missing-lifetime-specifier.stderr +++ b/tests/ui/suggestions/missing-lifetime-specifier.stderr @@ -1,5 +1,5 @@ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:23:44 + --> $DIR/missing-lifetime-specifier.rs:28:44 | LL | static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::new()); | ^^^ expected 2 lifetime parameters @@ -11,20 +11,7 @@ LL | static a: RefCell<HashMap<i32, Vec<Vec<Foo<'static, 'static>>>>> = RefC | ++++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:23:44 - | -LL | / thread_local! { -LL | | static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::new()); - | | ^^^ expected 2 lifetime parameters -LL | | -LL | | -LL | | } - | |_- - | - = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from - -error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:28:44 + --> $DIR/missing-lifetime-specifier.rs:32:44 | LL | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new()); | ^^^^ expected 2 lifetime parameters @@ -38,22 +25,7 @@ LL | static b: RefCell<HashMap<i32, Vec<Vec<&'static Bar<'static, 'static>>> | +++++++ ++++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:28:44 - | -LL | / thread_local! { -LL | | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new()); - | | ^^^^ expected 2 lifetime parameters - | | | - | | expected named lifetime parameter -LL | | -LL | | -LL | | } - | |_- - | - = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from - -error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:33:47 + --> $DIR/missing-lifetime-specifier.rs:36:47 | LL | static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new()); | ^ expected 2 lifetime parameters @@ -65,20 +37,7 @@ LL | static c: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = | +++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:33:47 - | -LL | / thread_local! { -LL | | static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new()); - | | ^ expected 2 lifetime parameters -LL | | -LL | | -LL | | } - | |_- - | - = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from - -error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:38:44 + --> $DIR/missing-lifetime-specifier.rs:40:44 | LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new()); | ^ ^ expected 2 lifetime parameters @@ -91,23 +50,8 @@ help: consider using the `'static` lifetime, but this is uncommon unless you're LL | static d: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new()); | +++++++ +++++++++++++++++ -error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:38:44 - | -LL | / thread_local! { -LL | | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new()); - | | ^ ^ expected 2 lifetime parameters - | | | - | | expected named lifetime parameter -LL | | -LL | | -LL | | } - | |_- - | - = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 4 lifetimes it is borrowed from - error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-specifier.rs:48:44 + --> $DIR/missing-lifetime-specifier.rs:49:44 | LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); | ^ expected named lifetime parameter @@ -118,22 +62,8 @@ help: consider using the `'static` lifetime, but this is uncommon unless you're LL | static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); | +++++++ -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-specifier.rs:48:44 - | -LL | / thread_local! { -LL | | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); - | | ^ expected named lifetime parameter -LL | | -LL | | -LL | | -LL | | } - | |_- - | - = help: this function's return type contains a borrowed value, but the signature does not say which one of `init`'s 3 lifetimes it is borrowed from - error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:44:44 + --> $DIR/missing-lifetime-specifier.rs:45:44 | LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -141,7 +71,7 @@ LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell: | expected 2 lifetime arguments | note: union defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:16:11 + --> $DIR/missing-lifetime-specifier.rs:21:11 | LL | pub union Qux<'t, 'k, I> { | ^^^ -- -- @@ -151,7 +81,7 @@ LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = | +++++++++ error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:48:45 + --> $DIR/missing-lifetime-specifier.rs:49:45 | LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -159,7 +89,7 @@ LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell | expected 2 lifetime arguments | note: trait defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:20:7 + --> $DIR/missing-lifetime-specifier.rs:25:7 | LL | trait Tar<'t, 'k, I> {} | ^^^ -- -- @@ -168,7 +98,7 @@ help: add missing lifetime argument LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new()); | +++++++++ -error: aborting due to 12 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0106, E0107. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/suggestions/option-content-move.fixed b/tests/ui/suggestions/option-content-move.fixed index 4a5a9483c20..ef07d55871e 100644 --- a/tests/ui/suggestions/option-content-move.fixed +++ b/tests/ui/suggestions/option-content-move.fixed @@ -1,4 +1,5 @@ //@ run-rustfix +#[allow(dead_code)] pub struct LipogramCorpora { selections: Vec<(char, Option<String>)>, } @@ -17,6 +18,7 @@ impl LipogramCorpora { } } +#[allow(dead_code)] pub struct LipogramCorpora2 { selections: Vec<(char, Result<String, String>)>, } diff --git a/tests/ui/suggestions/option-content-move.rs b/tests/ui/suggestions/option-content-move.rs index 90d05c74399..5be6358fd6a 100644 --- a/tests/ui/suggestions/option-content-move.rs +++ b/tests/ui/suggestions/option-content-move.rs @@ -1,4 +1,5 @@ //@ run-rustfix +#[allow(dead_code)] pub struct LipogramCorpora { selections: Vec<(char, Option<String>)>, } @@ -17,6 +18,7 @@ impl LipogramCorpora { } } +#[allow(dead_code)] pub struct LipogramCorpora2 { selections: Vec<(char, Result<String, String>)>, } diff --git a/tests/ui/suggestions/option-content-move.stderr b/tests/ui/suggestions/option-content-move.stderr index a382a04344a..b4ec5b180d2 100644 --- a/tests/ui/suggestions/option-content-move.stderr +++ b/tests/ui/suggestions/option-content-move.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of `selection.1` which is behind a shared reference - --> $DIR/option-content-move.rs:10:20 + --> $DIR/option-content-move.rs:11:20 | LL | if selection.1.unwrap().contains(selection.0) { | ^^^^^^^^^^^ -------- `selection.1` moved due to this method call @@ -19,7 +19,7 @@ LL | if selection.1.clone().unwrap().contains(selection.0) { | ++++++++ error[E0507]: cannot move out of `selection.1` which is behind a shared reference - --> $DIR/option-content-move.rs:28:20 + --> $DIR/option-content-move.rs:30:20 | LL | if selection.1.unwrap().contains(selection.0) { | ^^^^^^^^^^^ -------- `selection.1` moved due to this method call diff --git a/tests/ui/suggestions/silenced-binding-typo.stderr b/tests/ui/suggestions/silenced-binding-typo.stderr index c362d00c713..a1e8b9e30d4 100644 --- a/tests/ui/suggestions/silenced-binding-typo.stderr +++ b/tests/ui/suggestions/silenced-binding-typo.stderr @@ -1,10 +1,12 @@ error[E0425]: cannot find value `x` in this scope --> $DIR/silenced-binding-typo.rs:4:14 | +LL | let _x = 42; + | -- `_x` defined here LL | let _y = x; | ^ | -help: a local variable with a similar name exists, consider renaming `_x` into `x` +help: the leading underscore in `_x` marks it as unused, consider renaming it to `x` | LL | let x = 42; | ~ diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs index cab484a120c..445ea2de610 100644 --- a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs +++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.rs @@ -14,14 +14,12 @@ impl<T, S> Trait<T> for i32 { // Should not not trigger suggestion here... impl<T, S> Trait<T, S> for () {} //~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied -//~| ERROR `S` is not constrained //... but should do so in all of the below cases except the last one fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> { //~^ ERROR trait takes 1 generic argument but 2 generic arguments were supplied //~| ERROR trait takes 1 generic argument but 2 generic arguments were supplied //~| ERROR trait takes 1 generic argument but 2 generic arguments were supplied -//~| ERROR type annotations needed 3 } diff --git a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr index 99e81a9039e..06e2fa5d4d1 100644 --- a/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr +++ b/tests/ui/traits/associated_type_bound/116464-invalid-assoc-type-suggestion-in-trait-impl.stderr @@ -16,14 +16,8 @@ note: trait defined here, with 1 generic parameter: `T` LL | pub trait Trait<T> { | ^^^^^ - -error[E0207]: the type parameter `S` is not constrained by the impl trait, self type, or predicates - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:15:9 - | -LL | impl<T, S> Trait<T, S> for () {} - | ^ unconstrained type parameter - error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:20:12 + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:19:12 | LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> { | ^^^^^ expected 1 generic argument @@ -39,7 +33,7 @@ LL | fn func<T: Trait<u32, Assoc = String>>(t: T) -> impl Trait<(), i32> { | +++++++ error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:20:46 + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:19:46 | LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> { | ^^^^^ expected 1 generic argument @@ -55,7 +49,7 @@ LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), Assoc = i32> { | +++++++ error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:20:46 + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:19:46 | LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> { | ^^^^^ expected 1 generic argument @@ -71,14 +65,8 @@ help: replace the generic bound with the associated type LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), Assoc = i32> { | +++++++ -error[E0282]: type annotations needed - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:20:41 - | -LL | fn func<T: Trait<u32, String>>(t: T) -> impl Trait<(), i32> { - | ^^^^^^^^^^^^^^^^^^^ cannot infer type - error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:28:18 + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:26:18 | LL | struct Struct<T: Trait<u32, String>> { | ^^^^^ expected 1 generic argument @@ -94,7 +82,7 @@ LL | struct Struct<T: Trait<u32, Assoc = String>> { | +++++++ error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:33:23 + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:31:23 | LL | trait AnotherTrait<T: Trait<T, i32>> {} | ^^^^^ expected 1 generic argument @@ -110,7 +98,7 @@ LL | trait AnotherTrait<T: Trait<T, Assoc = i32>> {} | +++++++ error[E0107]: trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:36:9 + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:34:9 | LL | impl<T: Trait<u32, String>> Struct<T> {} | ^^^^^ expected 1 generic argument @@ -126,7 +114,7 @@ LL | impl<T: Trait<u32, Assoc = String>> Struct<T> {} | +++++++ error[E0107]: struct takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:42:58 + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:40:58 | LL | impl<T: Trait<u32, Assoc=String>, U> YetAnotherTrait for Struct<T, U> {} | ^^^^^^ - help: remove this generic argument @@ -134,12 +122,12 @@ LL | impl<T: Trait<u32, Assoc=String>, U> YetAnotherTrait for Struct<T, U> {} | expected 1 generic argument | note: struct defined here, with 1 generic parameter: `T` - --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:28:8 + --> $DIR/116464-invalid-assoc-type-suggestion-in-trait-impl.rs:26:8 | LL | struct Struct<T: Trait<u32, String>> { | ^^^^^^ - -error: aborting due to 11 previous errors +error: aborting due to 9 previous errors -Some errors have detailed explanations: E0107, E0207, E0282. +Some errors have detailed explanations: E0107, E0207. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/traits/generic_param_mismatch_in_unsatisfied_projection.rs b/tests/ui/traits/generic_param_mismatch_in_unsatisfied_projection.rs new file mode 100644 index 00000000000..bf1278f992b --- /dev/null +++ b/tests/ui/traits/generic_param_mismatch_in_unsatisfied_projection.rs @@ -0,0 +1,27 @@ +//! This test used to ICE: #121134 +//! The issue is that we're trying to prove a projection, but there's +//! no bound for the projection's trait, and the projection has the wrong +//! kind of generic parameter (lifetime vs type). +//! When actually calling the function with those broken bounds, trying to +//! instantiate the bounds with inference vars would ICE. +#![feature(unboxed_closures)] + +trait Output<'a> { + type Type; +} + +struct Wrapper; + +impl Wrapper { + fn do_something_wrapper<O, F>(&mut self, _: F) + where + F: for<'a> FnOnce(<F as Output<i32>>::Type), + //~^ ERROR: trait takes 0 generic arguments but 1 generic argument was supplied + { + } +} + +fn main() { + let mut wrapper = Wrapper; + wrapper.do_something_wrapper(|value| ()); +} diff --git a/tests/ui/traits/generic_param_mismatch_in_unsatisfied_projection.stderr b/tests/ui/traits/generic_param_mismatch_in_unsatisfied_projection.stderr new file mode 100644 index 00000000000..acda3418894 --- /dev/null +++ b/tests/ui/traits/generic_param_mismatch_in_unsatisfied_projection.stderr @@ -0,0 +1,19 @@ +error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/generic_param_mismatch_in_unsatisfied_projection.rs:18:33 + | +LL | F: for<'a> FnOnce(<F as Output<i32>>::Type), + | ^^^^^^ expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/generic_param_mismatch_in_unsatisfied_projection.rs:9:7 + | +LL | trait Output<'a> { + | ^^^^^^ +help: replace the generic bound with the associated type + | +LL | F: for<'a> FnOnce(<F as Output<Type = i32>>::Type), + | ++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/tests/ui/traits/issue-78372.stderr b/tests/ui/traits/issue-78372.stderr index 58a4c229e5e..cdcb0cdf259 100644 --- a/tests/ui/traits/issue-78372.stderr +++ b/tests/ui/traits/issue-78372.stderr @@ -55,12 +55,6 @@ LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {} = help: add `#![feature(dispatch_from_dyn)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures - --> $DIR/issue-78372.rs:3:1 - | -LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/issue-78372.rs:12:17 | @@ -88,6 +82,12 @@ LL | fn foo(self: Smaht<Self, T>); = note: type of `self` must be `Self` or a type that dereferences to it = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`) +error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures + --> $DIR/issue-78372.rs:3:1 + | +LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 8 previous errors Some errors have detailed explanations: E0038, E0307, E0378, E0412, E0658. diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr index d08bb4745bf..50b561dfd16 100644 --- a/tests/ui/traits/item-privacy.stderr +++ b/tests/ui/traits/item-privacy.stderr @@ -126,14 +126,15 @@ LL | S::B; | ^ associated item not found in `S` | = help: items from traits can only be used if the trait is in scope +help: there is a method `b` with a similar name + --> $DIR/item-privacy.rs:11:9 + | +LL | fn b(&self) { } + | ^^^^^^^^^^^ help: trait `B` which provides `B` is implemented but not in scope; perhaps you want to import it | LL + use assoc_const::B; | -help: there is a method `b` with a similar name - | -LL | S::b; - | ~ error[E0624]: associated constant `A` is private --> $DIR/item-privacy.rs:101:14 diff --git a/tests/ui/traits/next-solver/generalize/bivariant-alias.rs b/tests/ui/traits/next-solver/generalize/bivariant-alias.rs new file mode 100644 index 00000000000..b03d547838a --- /dev/null +++ b/tests/ui/traits/next-solver/generalize/bivariant-alias.rs @@ -0,0 +1,20 @@ +//@ revisions: old next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass + +// When generalizing an alias in a bivariant context, we have to set +// `has_unconstrained_ty_var` as we may otherwise never check for +// well-formedness of the generalized type, causing us to error due +// to ambiguity. +trait Trait { + type Assoc; +} + +struct BivariantArg<I, T: Trait<Assoc = I>>(T); + +fn generalize<T: Trait>(input: BivariantArg<T::Assoc, T>) { + let _generalized = input; +} + +pub fn main() {} diff --git a/tests/ui/traits/object/generics.rs b/tests/ui/traits/object/generics.rs index 462b0bc5bb7..0ae562c0d30 100644 --- a/tests/ui/traits/object/generics.rs +++ b/tests/ui/traits/object/generics.rs @@ -7,6 +7,7 @@ pub trait Trait2<A> { fn doit(&self) -> A; } +#[allow(dead_code)] pub struct Impl<A1, A2, A3> { m1: marker::PhantomData<(A1,A2,A3)>, /* diff --git a/tests/ui/traits/vtable/vtable-vacant.rs b/tests/ui/traits/vtable/vtable-vacant.rs index 26de3f60621..b3c76815703 100644 --- a/tests/ui/traits/vtable/vtable-vacant.rs +++ b/tests/ui/traits/vtable/vtable-vacant.rs @@ -1,7 +1,6 @@ //@ build-fail #![feature(rustc_attrs)] #![feature(negative_impls)] -#![allow(where_clauses_object_safety)] // B --> A diff --git a/tests/ui/traits/vtable/vtable-vacant.stderr b/tests/ui/traits/vtable/vtable-vacant.stderr index 9ce1d0b7632..f6961ca010e 100644 --- a/tests/ui/traits/vtable/vtable-vacant.stderr +++ b/tests/ui/traits/vtable/vtable-vacant.stderr @@ -7,7 +7,7 @@ error: vtable entries for `<S as B>`: [ Method(<S as B>::foo_b1), Vacant, ] - --> $DIR/vtable-vacant.rs:15:1 + --> $DIR/vtable-vacant.rs:14:1 | LL | trait B: A { | ^^^^^^^^^^ diff --git a/tests/ui/transmutability/issue-101739-2.rs b/tests/ui/transmutability/issue-101739-2.rs index e2cec24aac1..1c0bd29d707 100644 --- a/tests/ui/transmutability/issue-101739-2.rs +++ b/tests/ui/transmutability/issue-101739-2.rs @@ -15,7 +15,6 @@ mod assert { >() where Dst: BikeshedIntrinsicFrom< //~ ERROR trait takes at most 2 generic arguments but 5 generic arguments were supplied - //~^ ERROR: the constant `ASSUME_ALIGNMENT` is not of type `Assume` Src, ASSUME_ALIGNMENT, //~ ERROR: mismatched types ASSUME_LIFETIMES, diff --git a/tests/ui/transmutability/issue-101739-2.stderr b/tests/ui/transmutability/issue-101739-2.stderr index 639b4460892..38912696c18 100644 --- a/tests/ui/transmutability/issue-101739-2.stderr +++ b/tests/ui/transmutability/issue-101739-2.stderr @@ -9,29 +9,13 @@ LL | | ASSUME_VALIDITY, LL | | ASSUME_VISIBILITY, | |_____________________________- help: remove these generic arguments -error: the constant `ASSUME_ALIGNMENT` is not of type `Assume` - --> $DIR/issue-101739-2.rs:17:14 - | -LL | Dst: BikeshedIntrinsicFrom< - | ______________^ -LL | | -LL | | Src, -LL | | ASSUME_ALIGNMENT, -... | -LL | | ASSUME_VISIBILITY, -LL | | >, - | |_________^ expected `Assume`, found `bool` - | -note: required by a bound in `BikeshedIntrinsicFrom` - --> $SRC_DIR/core/src/mem/transmutability.rs:LL:COL - error[E0308]: mismatched types - --> $DIR/issue-101739-2.rs:20:13 + --> $DIR/issue-101739-2.rs:19:13 | LL | ASSUME_ALIGNMENT, | ^^^^^^^^^^^^^^^^ expected `Assume`, found `bool` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0107, E0308. For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/type-alias-impl-trait/coherence.stderr b/tests/ui/type-alias-impl-trait/coherence.classic.stderr index 266a532a1db..ff059bc5806 100644 --- a/tests/ui/type-alias-impl-trait/coherence.stderr +++ b/tests/ui/type-alias-impl-trait/coherence.classic.stderr @@ -1,5 +1,5 @@ error[E0117]: only traits defined in the current crate can be implemented for arbitrary types - --> $DIR/coherence.rs:14:1 + --> $DIR/coherence.rs:16:1 | LL | impl foreign_crate::ForeignTrait for AliasOfForeignType<()> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------- diff --git a/tests/ui/type-alias-impl-trait/coherence.next.stderr b/tests/ui/type-alias-impl-trait/coherence.next.stderr new file mode 100644 index 00000000000..dab2786c1f0 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/coherence.next.stderr @@ -0,0 +1,14 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/coherence.rs:16:1 + | +LL | impl foreign_crate::ForeignTrait for AliasOfForeignType<()> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------- + | | | + | | `AliasOfForeignType<()>` is not defined in the current crate + | impl doesn't use only types from inside the current crate + | + = note: define and implement a trait or new type instead + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0117`. diff --git a/tests/ui/type-alias-impl-trait/coherence.rs b/tests/ui/type-alias-impl-trait/coherence.rs index 641c0fac17a..760e5210c5b 100644 --- a/tests/ui/type-alias-impl-trait/coherence.rs +++ b/tests/ui/type-alias-impl-trait/coherence.rs @@ -1,4 +1,6 @@ //@ aux-build:foreign-crate.rs +//@ revisions: classic next +//@[next] compile-flags: -Znext-solver #![feature(type_alias_impl_trait)] extern crate foreign_crate; diff --git a/tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr b/tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr index 6a1a770228d..3b6999cabc4 100644 --- a/tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr +++ b/tests/ui/type-alias-impl-trait/const_generic_type.infer.stderr @@ -1,5 +1,5 @@ error: `Bar` is forbidden as the type of a const generic parameter - --> $DIR/const_generic_type.rs:7:24 + --> $DIR/const_generic_type.rs:8:24 | LL | async fn test<const N: crate::Bar>() { | ^^^^^^^^^^ diff --git a/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr b/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr index a1a69bfaca3..56a10201651 100644 --- a/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr +++ b/tests/ui/type-alias-impl-trait/const_generic_type.no_infer.stderr @@ -1,13 +1,13 @@ -error[E0283]: type annotations needed - --> $DIR/const_generic_type.rs:7:1 +error: unconstrained opaque type + --> $DIR/const_generic_type.rs:5:12 | -LL | async fn test<const N: crate::Bar>() { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type +LL | type Bar = impl std::fmt::Display; + | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: cannot satisfy `_: std::fmt::Display` + = note: `Bar` must be used in combination with a concrete type within the same module error: `Bar` is forbidden as the type of a const generic parameter - --> $DIR/const_generic_type.rs:7:24 + --> $DIR/const_generic_type.rs:8:24 | LL | async fn test<const N: crate::Bar>() { | ^^^^^^^^^^ @@ -16,4 +16,3 @@ LL | async fn test<const N: crate::Bar>() { error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/type-alias-impl-trait/const_generic_type.rs b/tests/ui/type-alias-impl-trait/const_generic_type.rs index 95a5e1c6286..bfd06826f00 100644 --- a/tests/ui/type-alias-impl-trait/const_generic_type.rs +++ b/tests/ui/type-alias-impl-trait/const_generic_type.rs @@ -3,10 +3,10 @@ #![feature(type_alias_impl_trait)] type Bar = impl std::fmt::Display; +//[no_infer]~^ ERROR: unconstrained opaque type async fn test<const N: crate::Bar>() { - //[no_infer]~^ ERROR: type annotations needed - //~^^ ERROR: `Bar` is forbidden as the type of a const generic parameter + //~^ ERROR: `Bar` is forbidden as the type of a const generic parameter #[cfg(infer)] let x: u32 = N; } diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs index 6aa032d7ed8..92c2e7b4884 100644 --- a/tests/ui/unpretty/expanded-exhaustive.rs +++ b/tests/ui/unpretty/expanded-exhaustive.rs @@ -25,6 +25,7 @@ #![feature(trait_alias)] #![feature(try_blocks)] #![feature(unnamed_fields)] +#![feature(unsafe_extern_blocks)] #![feature(yeet_expr)] #![allow(incomplete_features)] @@ -473,8 +474,8 @@ mod items { /// ItemKind::ForeignMod mod item_foreign_mod { - extern "C++" {} - extern {} + unsafe extern "C++" {} + unsafe extern {} } /// ItemKind::GlobalAsm diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout index 8737063bf3c..137a8aa5510 100644 --- a/tests/ui/unpretty/expanded-exhaustive.stdout +++ b/tests/ui/unpretty/expanded-exhaustive.stdout @@ -26,6 +26,7 @@ #![feature(trait_alias)] #![feature(try_blocks)] #![feature(unnamed_fields)] +#![feature(unsafe_extern_blocks)] #![feature(yeet_expr)] #![allow(incomplete_features)] #[prelude_import] @@ -82,8 +83,7 @@ mod expressions { fn expr_const_block() { const {}; const { 1 }; - const - { + const { struct S; }; } @@ -451,8 +451,8 @@ mod items { mod item_mod { } /// ItemKind::ForeignMod mod item_foreign_mod { - extern "C++" {} - extern {} + unsafe extern "C++" {} + unsafe extern {} } /// ItemKind::GlobalAsm mod item_global_asm { diff --git a/tests/ui/unused-crate-deps/deny-attr.rs b/tests/ui/unused-crate-deps/deny-attr.rs index 3b2e8b5677e..71f478b6b7d 100644 --- a/tests/ui/unused-crate-deps/deny-attr.rs +++ b/tests/ui/unused-crate-deps/deny-attr.rs @@ -4,6 +4,6 @@ //@ aux-crate:bar=bar.rs #![deny(unused_crate_dependencies)] -//~^ ERROR external crate `bar` unused in +//~^ ERROR extern crate `bar` is unused in fn main() {} diff --git a/tests/ui/unused-crate-deps/deny-attr.stderr b/tests/ui/unused-crate-deps/deny-attr.stderr index 89e87c9d5ac..7540d9cdc16 100644 --- a/tests/ui/unused-crate-deps/deny-attr.stderr +++ b/tests/ui/unused-crate-deps/deny-attr.stderr @@ -1,9 +1,10 @@ -error: external crate `bar` unused in `deny_attr`: remove the dependency or add `use bar as _;` +error: extern crate `bar` is unused in crate `deny_attr` --> $DIR/deny-attr.rs:6:1 | LL | #![deny(unused_crate_dependencies)] | ^ | + = help: remove the dependency or add `use bar as _;` to the crate root note: the lint level is defined here --> $DIR/deny-attr.rs:6:9 | diff --git a/tests/ui/unused-crate-deps/deny-cmdline.rs b/tests/ui/unused-crate-deps/deny-cmdline.rs index d32e8e205af..890c01e0016 100644 --- a/tests/ui/unused-crate-deps/deny-cmdline.rs +++ b/tests/ui/unused-crate-deps/deny-cmdline.rs @@ -5,4 +5,4 @@ //@ aux-crate:bar=bar.rs fn main() {} -//~^ ERROR external crate `bar` unused in +//~^ ERROR extern crate `bar` is unused in diff --git a/tests/ui/unused-crate-deps/deny-cmdline.stderr b/tests/ui/unused-crate-deps/deny-cmdline.stderr index fc526878ef0..b48d1ec1ba9 100644 --- a/tests/ui/unused-crate-deps/deny-cmdline.stderr +++ b/tests/ui/unused-crate-deps/deny-cmdline.stderr @@ -1,9 +1,10 @@ -error: external crate `bar` unused in `deny_cmdline`: remove the dependency or add `use bar as _;` +error: extern crate `bar` is unused in crate `deny_cmdline` --> $DIR/deny-cmdline.rs:7:1 | LL | fn main() {} | ^ | + = help: remove the dependency or add `use bar as _;` to the crate root = note: requested on the command line with `-D unused-crate-dependencies` error: aborting due to 1 previous error diff --git a/tests/ui/unused-crate-deps/libfib.rs b/tests/ui/unused-crate-deps/libfib.rs index 8a5ec758e56..d7729c9ebe7 100644 --- a/tests/ui/unused-crate-deps/libfib.rs +++ b/tests/ui/unused-crate-deps/libfib.rs @@ -5,7 +5,7 @@ //@ compile-flags:--crate-type lib -Wunused-crate-dependencies pub fn fib(n: u32) -> Vec<u32> { -//~^ WARNING external crate `bar` unused in +//~^ WARNING extern crate `bar` is unused in let mut prev = 0; let mut cur = 1; let mut v = vec![]; diff --git a/tests/ui/unused-crate-deps/libfib.stderr b/tests/ui/unused-crate-deps/libfib.stderr index 15833126bd6..da6893f5034 100644 --- a/tests/ui/unused-crate-deps/libfib.stderr +++ b/tests/ui/unused-crate-deps/libfib.stderr @@ -1,9 +1,10 @@ -warning: external crate `bar` unused in `libfib`: remove the dependency or add `use bar as _;` +warning: extern crate `bar` is unused in crate `libfib` --> $DIR/libfib.rs:7:1 | LL | pub fn fib(n: u32) -> Vec<u32> { | ^ | + = help: remove the dependency or add `use bar as _;` to the crate root = note: requested on the command line with `-W unused-crate-dependencies` warning: 1 warning emitted diff --git a/tests/ui/unused-crate-deps/unused-aliases.rs b/tests/ui/unused-crate-deps/unused-aliases.rs index f86f6bbf356..2db50cec971 100644 --- a/tests/ui/unused-crate-deps/unused-aliases.rs +++ b/tests/ui/unused-crate-deps/unused-aliases.rs @@ -6,7 +6,7 @@ //@ aux-crate:barbar=bar.rs #![warn(unused_crate_dependencies)] -//~^ WARNING external crate `barbar` unused in +//~^ WARNING extern crate `barbar` is unused in use bar as _; diff --git a/tests/ui/unused-crate-deps/unused-aliases.stderr b/tests/ui/unused-crate-deps/unused-aliases.stderr index c8c6c4507b0..d4093b102d5 100644 --- a/tests/ui/unused-crate-deps/unused-aliases.stderr +++ b/tests/ui/unused-crate-deps/unused-aliases.stderr @@ -1,9 +1,10 @@ -warning: external crate `barbar` unused in `unused_aliases`: remove the dependency or add `use barbar as _;` +warning: extern crate `barbar` is unused in crate `unused_aliases` --> $DIR/unused-aliases.rs:8:1 | LL | #![warn(unused_crate_dependencies)] | ^ | + = help: remove the dependency or add `use barbar as _;` to the crate root note: the lint level is defined here --> $DIR/unused-aliases.rs:8:9 | diff --git a/tests/ui/unused-crate-deps/warn-attr.rs b/tests/ui/unused-crate-deps/warn-attr.rs index b558c0678d6..c40ed001732 100644 --- a/tests/ui/unused-crate-deps/warn-attr.rs +++ b/tests/ui/unused-crate-deps/warn-attr.rs @@ -5,6 +5,6 @@ //@ aux-crate:bar=bar.rs #![warn(unused_crate_dependencies)] -//~^ WARNING external crate `bar` unused in +//~^ WARNING extern crate `bar` is unused in fn main() {} diff --git a/tests/ui/unused-crate-deps/warn-attr.stderr b/tests/ui/unused-crate-deps/warn-attr.stderr index 0d38315704b..2c72961093c 100644 --- a/tests/ui/unused-crate-deps/warn-attr.stderr +++ b/tests/ui/unused-crate-deps/warn-attr.stderr @@ -1,9 +1,10 @@ -warning: external crate `bar` unused in `warn_attr`: remove the dependency or add `use bar as _;` +warning: extern crate `bar` is unused in crate `warn_attr` --> $DIR/warn-attr.rs:7:1 | LL | #![warn(unused_crate_dependencies)] | ^ | + = help: remove the dependency or add `use bar as _;` to the crate root note: the lint level is defined here --> $DIR/warn-attr.rs:7:9 | diff --git a/tests/ui/unused-crate-deps/warn-cmdline-static.rs b/tests/ui/unused-crate-deps/warn-cmdline-static.rs index ccb404e3033..eb51543ad1a 100644 --- a/tests/ui/unused-crate-deps/warn-cmdline-static.rs +++ b/tests/ui/unused-crate-deps/warn-cmdline-static.rs @@ -7,4 +7,4 @@ //@ no-prefer-dynamic fn main() {} -//~^ WARNING external crate `bar` unused in +//~^ WARNING extern crate `bar` is unused in diff --git a/tests/ui/unused-crate-deps/warn-cmdline-static.stderr b/tests/ui/unused-crate-deps/warn-cmdline-static.stderr index 65956461d64..79a3ade8719 100644 --- a/tests/ui/unused-crate-deps/warn-cmdline-static.stderr +++ b/tests/ui/unused-crate-deps/warn-cmdline-static.stderr @@ -1,9 +1,10 @@ -warning: external crate `bar` unused in `warn_cmdline_static`: remove the dependency or add `use bar as _;` +warning: extern crate `bar` is unused in crate `warn_cmdline_static` --> $DIR/warn-cmdline-static.rs:9:1 | LL | fn main() {} | ^ | + = help: remove the dependency or add `use bar as _;` to the crate root = note: requested on the command line with `-W unused-crate-dependencies` warning: 1 warning emitted diff --git a/tests/ui/unused-crate-deps/warn-cmdline.rs b/tests/ui/unused-crate-deps/warn-cmdline.rs index 8d390e02ca5..cdeff5e5f60 100644 --- a/tests/ui/unused-crate-deps/warn-cmdline.rs +++ b/tests/ui/unused-crate-deps/warn-cmdline.rs @@ -6,4 +6,4 @@ //@ aux-crate:bar=bar.rs fn main() {} -//~^ WARNING external crate `bar` unused in +//~^ WARNING extern crate `bar` is unused in diff --git a/tests/ui/unused-crate-deps/warn-cmdline.stderr b/tests/ui/unused-crate-deps/warn-cmdline.stderr index ea675ba9a1e..f5df83ca884 100644 --- a/tests/ui/unused-crate-deps/warn-cmdline.stderr +++ b/tests/ui/unused-crate-deps/warn-cmdline.stderr @@ -1,9 +1,10 @@ -warning: external crate `bar` unused in `warn_cmdline`: remove the dependency or add `use bar as _;` +warning: extern crate `bar` is unused in crate `warn_cmdline` --> $DIR/warn-cmdline.rs:8:1 | LL | fn main() {} | ^ | + = help: remove the dependency or add `use bar as _;` to the crate root = note: requested on the command line with `-W unused-crate-dependencies` warning: 1 warning emitted diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs index db155f4fa3c..3f43fbfc0cf 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs @@ -1,7 +1,6 @@ trait Trait<const N: Trait = bar> { //~^ ERROR cannot find value `bar` in this scope //~| ERROR cycle detected when computing type of `Trait::N` - //~| ERROR cycle detected when computing type of `Trait::N` //~| ERROR the trait `Trait` cannot be made into an object //~| ERROR the trait `Trait` cannot be made into an object //~| ERROR the trait `Trait` cannot be made into an object @@ -11,20 +10,20 @@ trait Trait<const N: Trait = bar> { //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects] //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! fn fnc<const N: Trait = u32>(&self) -> Trait { - //~^ ERROR the name `N` is already used for a generic parameter in this item's generic parameters - //~| ERROR expected value, found builtin type `u32` - //~| ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - //~| ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `Trait` cannot be made into an object - //~| ERROR `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter - //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects] - //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects] - //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects] - //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + //~^ ERROR the name `N` is already used for a generic parameter in this item's generic parameters + //~| ERROR expected value, found builtin type `u32` + //~| ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions + //~| ERROR associated item referring to unboxed trait object for its own trait + //~| ERROR the trait `Trait` cannot be made into an object + //~| ERROR `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter + //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects] + //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects] + //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects] + //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! bar - //~^ ERROR cannot find value `bar` in this scope + //~^ ERROR cannot find value `bar` in this scope } } diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr index cf985d9d1fd..f2456f99e62 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr @@ -1,5 +1,5 @@ error[E0403]: the name `N` is already used for a generic parameter in this item's generic parameters - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:18 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:18 | LL | trait Trait<const N: Trait = bar> { | - first use of `N` @@ -14,13 +14,13 @@ LL | trait Trait<const N: Trait = bar> { | ^^^ not found in this scope error[E0423]: expected value, found builtin type `u32` - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:29 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:29 | LL | fn fnc<const N: Trait = u32>(&self) -> Trait { | ^^^ not a value error[E0425]: cannot find value `bar` in this scope - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:26:9 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:25:9 | LL | bar | ^^^ not found in this scope @@ -53,28 +53,14 @@ LL | trait Trait<const N: Trait = bar> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = 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 `Trait::N` - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:13 - | -LL | trait Trait<const N: Trait = bar> { - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: ...which immediately requires computing type of `Trait::N` again -note: cycle used when computing explicit predicates of trait `Trait` - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:1 - | -LL | trait Trait<const N: Trait = bar> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = 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: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:12 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:12 | LL | fn fnc<const N: Trait = u32>(&self) -> Trait { | ^^^^^^^^^^^^^^^^^^^^ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:21 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:21 | LL | fn fnc<const N: Trait = u32>(&self) -> Trait { | ^^^^^ @@ -87,7 +73,7 @@ LL | fn fnc<const N: dyn Trait = u32>(&self) -> Trait { | +++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:44 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:44 | LL | fn fnc<const N: Trait = u32>(&self) -> Trait { | ^^^^^ @@ -120,7 +106,7 @@ LL | trait Trait<const N: Trait = bar> { | ^^^^^ `Trait` 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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:8 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8 | LL | trait Trait<const N: Trait = bar> { | ----- this trait cannot be made into an object... @@ -136,7 +122,7 @@ LL | trait Trait<const N: Trait = bar> { | ^^^^^^^^^^^^^^^^^^^^ `Trait` 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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:8 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8 | LL | trait Trait<const N: Trait = bar> { | ----- this trait cannot be made into an object... @@ -154,7 +140,7 @@ LL | trait Trait<const N: Trait = bar> { = note: the only supported types are integers, `bool` and `char` error: associated item referring to unboxed trait object for its own trait - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:44 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:44 | LL | trait Trait<const N: Trait = bar> { | ----- in this trait @@ -168,7 +154,7 @@ LL | fn fnc<const N: Trait = u32>(&self) -> Self { | ~~~~ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:21 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:21 | LL | fn fnc<const N: Trait = u32>(&self) -> Trait { | ^^^^^ @@ -182,13 +168,13 @@ LL | fn fnc<const N: dyn Trait = u32>(&self) -> Trait { | +++ error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:21 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:21 | LL | fn fnc<const N: Trait = u32>(&self) -> Trait { | ^^^^^ `Trait` 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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:8 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8 | LL | trait Trait<const N: Trait = bar> { | ----- this trait cannot be made into an object... @@ -204,7 +190,7 @@ LL | trait Trait<const N: Trait = bar> { | ^^^^^^^^^^^^^^^^^^^^ `Trait` 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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:8 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:8 | LL | trait Trait<const N: Trait = bar> { | ----- this trait cannot be made into an object... @@ -215,14 +201,14 @@ LL | fn fnc<const N: Trait = u32>(&self) -> Trait { = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `(dyn Trait<{const error}> + 'static)` is forbidden as the type of a const generic parameter - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:13:21 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:12:21 | LL | fn fnc<const N: Trait = u32>(&self) -> Trait { | ^^^^^ | = note: the only supported types are integers, `bool` and `char` -error: aborting due to 14 previous errors; 5 warnings emitted +error: aborting due to 13 previous errors; 5 warnings emitted Some errors have detailed explanations: E0038, E0391, E0403, E0423, E0425. For more information about an error, try `rustc --explain E0038`. 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 index 2995f26af4a..a953f1818c5 100644 --- 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 @@ -1,15 +1,11 @@ // Regression test for ICE #122989 trait Foo<const N: Bar<2>> { -//~^ 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() { - } + //~^ 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 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<const M: Foo<2>> {} 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 index e6fdc440873..a0fd11de2dc 100644 --- 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 @@ -13,7 +13,7 @@ LL | trait Foo<const N: dyn Bar<2>> { | +++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:15:20 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:20 | LL | trait Bar<const M: Foo<2>> {} | ^^^^^^ @@ -32,7 +32,7 @@ LL | trait Foo<const N: Bar<2>> { | ^^^^^^^^^^^^^^^ | note: ...which requires computing type of `Bar::M`... - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:15:11 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:11 | LL | trait Bar<const M: Foo<2>> {} | ^^^^^^^^^^^^^^^ @@ -44,26 +44,6 @@ LL | trait Foo<const N: Bar<2>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = 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<const N: Bar<2>> { - | ^^^^^^^^^^^^^^^ - | -note: ...which requires computing type of `Bar::M`... - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:15:11 - | -LL | trait Bar<const M: Foo<2>> {} - | ^^^^^^^^^^^^^^^ - = 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<const N: Bar<2>> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - = 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 | @@ -71,43 +51,20 @@ LL | trait Foo<const N: Bar<2>> { | ^ `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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:8 - | -LL | trait Foo<const N: Bar<2>> { - | --- 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<const N: Bar<2>> { - | ^^^^^^^^^^^^^^^ `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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:8 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:8:8 | LL | trait Foo<const N: Bar<2>> { | --- this trait cannot be made into an object... ... -LL | fn func() { +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) { +LL | fn func(&self) {} | +++++ help: alternatively, consider constraining `func` so it does not apply to trait objects | -LL | fn func() where Self: Sized { +LL | fn func() where Self: Sized {} | +++++++++++++++++ error: `(dyn Bar<2> + 'static)` is forbidden as the type of a const generic parameter @@ -119,61 +76,37 @@ LL | trait Foo<const N: Bar<2>> { = 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 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:11 | LL | trait Bar<const M: Foo<2>> {} | ^^^^^^^^^^^^^^^ `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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:8 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:8:8 | LL | trait Foo<const N: Bar<2>> { | --- this trait cannot be made into an object... ... -LL | fn func() { +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) { +LL | fn func(&self) {} | +++++ help: alternatively, consider constraining `func` so it does not apply to trait objects | -LL | fn func() where Self: Sized { +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 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:20 | LL | trait Bar<const M: Foo<2>> {} | ^^^^^^ | = 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<const N: Bar<2>> { - | ^^^^^^^^^^^^^^^ `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 <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:8 - | -LL | trait Foo<const N: Bar<2>> { - | --- 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 +error: aborting due to 5 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/where-clauses/self-in-where-clause-allowed.rs b/tests/ui/where-clauses/self-in-where-clause-allowed.rs index fd2cfe2bf65..a4c2d82b483 100644 --- a/tests/ui/where-clauses/self-in-where-clause-allowed.rs +++ b/tests/ui/where-clauses/self-in-where-clause-allowed.rs @@ -1,7 +1,6 @@ //@ check-fail #![feature(auto_traits)] -#![deny(where_clauses_object_safety)] auto trait AutoTrait {} diff --git a/tests/ui/where-clauses/self-in-where-clause-allowed.stderr b/tests/ui/where-clauses/self-in-where-clause-allowed.stderr index 7f92ac102f0..5d23c4bee00 100644 --- a/tests/ui/where-clauses/self-in-where-clause-allowed.stderr +++ b/tests/ui/where-clauses/self-in-where-clause-allowed.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `dyn Trait: AutoTrait` is not satisfied - --> $DIR/self-in-where-clause-allowed.rs:22:18 + --> $DIR/self-in-where-clause-allowed.rs:21:18 | LL | trait_object.autotrait_bound(); | ^^^^^^^^^^^^^^^ the trait `AutoTrait` is not implemented for `dyn Trait` | note: required by a bound in `Trait::autotrait_bound` - --> $DIR/self-in-where-clause-allowed.rs:13:43 + --> $DIR/self-in-where-clause-allowed.rs:12:43 | LL | fn autotrait_bound(&self) where Self: AutoTrait {} | ^^^^^^^^^ required by this bound in `Trait::autotrait_bound` diff --git a/triagebot.toml b/triagebot.toml index 23e5c0a27f3..3abff0f1c78 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -330,6 +330,7 @@ trigger_files = [ "src/tools/compiletest", "src/tools/tidy", "src/tools/rustdoc-gui-test", + "src/tools/libcxx-version", ] [autolabel."T-infra"] @@ -428,6 +429,12 @@ trigger_files = [ "tests/ui/stack-protector" ] +[autolabel."A-run-make"] +trigger_files = [ + "tests/run-make", + "src/tools/run-make-support" +] + [notify-zulip."I-prioritize"] zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts topic = "#{number} {title}" @@ -683,7 +690,13 @@ message = "Some changes occurred in GUI tests." cc = ["@GuillaumeGomez"] [mentions."tests/run-make/"] -message = "Some changes occurred in run-make tests." +message = """ +This PR modifies `tests/run-make/`. If this PR is trying to port a Makefile +run-make test to use rmake.rs, please update the +[run-make port tracking issue](https://github.com/rust-lang/rust/issues/121876) +so we can track our progress. You can either modify the tracking issue +directly, or you can comment on the tracking issue and link this PR. +""" cc = ["@jieyouxu"] [mentions."src/librustdoc/html/static/css/themes/ayu.css"] @@ -1117,6 +1130,7 @@ project-exploit-mitigations = [ "/src/tools/tidy" = ["bootstrap"] "/src/tools/x" = ["bootstrap"] "/src/tools/rustdoc-gui-test" = ["bootstrap", "@onur-ozkan"] +"/src/tools/libcxx-version" = ["@onur-ozkan"] # Enable tracking of PR review assignment # Documentation at: https://forge.rust-lang.org/triagebot/pr-assignment-tracking.html |
